2.2.0 Pushing beta to prod, lots of changes

This commit is contained in:
Trevor Squillario 2012-10-18 20:29:55 -04:00
parent db8cb0865a
commit 58d46ec544
16 changed files with 752 additions and 399 deletions

34
README
View file

@ -2,17 +2,35 @@ MiniSub - HTML5 Mini Player for Subsonic
Imagine you can stream all your music from home, to any device, where ever you are. That is Subsonic! Now imagine having a Web App to stream your music that is as beautiful and well designed as it is functional, that is MiniSub! Imagine you can stream all your music from home, to any device, where ever you are. That is Subsonic! Now imagine having a Web App to stream your music that is as beautiful and well designed as it is functional, that is MiniSub!
MiniSub is an HTML5 Mini Player for the Subsonic streaming server. MiniSub is an HTML5 Web Player for the Subsonic streaming server.
Features Features
- HTML5 Audio with Flash fallback (provided by the SoundManager2 library)
- Flexible Layout (will scale to whatever size your browser window is) - Flexible Layout (will scale to whatever size your browser window is)
- Customizable (features can be turned on/off and settings are saved) - Keyboard shortcuts (back, forward, play/pause, skip to artist, volume control)
- Keyboard shortcuts (back, forward, play/pause, skip to artist) - Playlist support (create new, add to existing, delete)
- Playlists (create new, add to existing, delete) - Podcast support (includes description field on hover)
- Artist/Album Ratings - Favorite/Starred support for Albums & Songs
- Chat and Now Playing - Chat support (when the chat window is open it will auto-update in the background)
- Last.fm - Now Playing support (see what others are streaming at the moment)
- Easy installation (Chrome App or manual install)
- FF/Chome support (IE9 works but is a little rough around the edges)
- Sortable Columns
- Light/Dark Theme
- Last.fm support
- Autopilot Mode (click one button and songs continue to play)
- AutoSave Mode (saves position and current playlist if you close or refresh your browser)
You will need a Subsonic server to be able to play your own music. Subsonic is a free, web-based media streamer, providing ubiquitous access to your music. Use it to share your music with friends, or to listen to your own music while at work. Please see http://www.subsonic.org You will need a Subsonic server to be able to play your own music. Subsonic is a free, web-based media streamer, providing ubiquitous access to your music. Use it to share your music with friends, or to listen to your own music while at work. Please see http://www.subsonic.org
Change Log inside... Chrome App: https://chrome.google.com/webstore/detail/minisub/jccdpflnecheidefpofmlblgebobbloc
Forum: http://forum.subsonic.org/forum/viewforum.php?f=12
Donations: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VMTENRSJWQ234
Change Log inside...
**Permissions**
* You will have to allow MiniSub to "Access your data on all websites". This is required because your Subsonic server could be at any URL `http://*/*` or `https://*/*`
* I NEVER access, read, modify, store, or transmit your personal data.
* [https://github.com/tsquillario/MiniSub/blob/master/manifest.json](https://github.com/tsquillario/MiniSub/blob/master/manifest.json)
* [http://developer.chrome.com/extensions/xhr.html](http://developer.chrome.com/extensions/xhr.html)

View file

@ -1,51 +1,36 @@
======= MiniSub - HTML5 Mini Player for Subsonic
MiniSub
=======
**HTML5 Mini Player for Subsonic**
Imagine you can stream all your music from home, to any device, where ever you Imagine you can stream all your music from home, to any device, where ever you are. That is Subsonic! Now imagine having a Web App to stream your music that is as beautiful and well designed as it is functional, that is MiniSub!
are. That is Subsonic! Now imagine having a Web App to stream your music that
is as beautiful and well designed as it is functional, that is MiniSub!
MiniSub is an HTML5 Mini Player for the Subsonic streaming server. MiniSub is an HTML5 Web Player for the Subsonic streaming server.
Features Features
```````` - HTML5 Audio with Flash fallback (provided by the SoundManager2 library)
* Flexible Layout (will scale to whatever size your browser window is) - Flexible Layout (will scale to whatever size your browser window is)
* Customizable (features can be turned on/off and settings are saved) - Keyboard shortcuts (back, forward, play/pause, skip to artist, volume control)
* Keyboard shortcuts (back, forward, play/pause, skip to artist) - Playlist support (create new, add to existing, delete)
* Playlists (create new, add to existing, delete) - Podcast support (includes description field on hover)
* Artist/Album Ratings - Favorite/Starred support for Albums & Songs
* Chat and Now Playing - Chat support (when the chat window is open it will auto-update in the background)
* Last.fm - Now Playing support (see what others are streaming at the moment)
* Supports Podcasts. - Easy installation (Chrome App or manual install)
- FF/Chome support (IE9 works but is a little rough around the edges)
- Sortable Columns
- Light/Dark Theme
- Last.fm support
- Autopilot Mode (click one button and songs continue to play)
- AutoSave Mode (saves position and current playlist if you close or refresh your browser)
You will need a Subsonic server to be able to play your own music. Subsonic is You will need a Subsonic server to be able to play your own music. Subsonic is a free, web-based media streamer, providing ubiquitous access to your music. Use it to share your music with friends, or to listen to your own music while at work. Please see http://www.subsonic.org
a free, web-based media streamer, providing ubiquitous access to your music.
Use it to share your music with friends, or to listen to your own music while Chrome App: https://chrome.google.com/webstore/detail/minisub/jccdpflnecheidefpofmlblgebobbloc
at work. Please see http://www.subsonic.org Forum: http://forum.subsonic.org/forum/viewforum.php?f=12
Donations: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VMTENRSJWQ234
Change Log inside... Change Log inside...
License **Permissions**
``````` * You will have to allow MiniSub to "Access your data on all websites". This is required because your Subsonic server could be at any URL `http://*/*` or `https://*/*`
Copyright (c) 2011-2012 Trevor Squillario * I NEVER access, read, modify, store, or transmit your personal data.
https://github.com/tsquillario/MiniSub * [https://github.com/tsquillario/MiniSub/blob/master/manifest.json](https://github.com/tsquillario/MiniSub/blob/master/manifest.json)
* [http://developer.chrome.com/extensions/xhr.html](http://developer.chrome.com/extensions/xhr.html)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

View file

@ -17,6 +17,7 @@
<script src="js/plugins/jquery.dateFormat-1.0.js" type="text/javascript"></script> <script src="js/plugins/jquery.dateFormat-1.0.js" type="text/javascript"></script>
<script src="js/plugins/jquery.disable.text.select.pack.js" type="text/javascript"></script> <script src="js/plugins/jquery.disable.text.select.pack.js" type="text/javascript"></script>
<script src="js/plugins/jquery.hotkeys.js" type="text/javascript"></script> <script src="js/plugins/jquery.hotkeys.js" type="text/javascript"></script>
<script src="js/plugins/jquery.stupidtable.js" type="text/javascript"></script>
<script src="js/plugins/jquery.linkify-1.0-min.js" type="text/javascript"></script> <script src="js/plugins/jquery.linkify-1.0-min.js" type="text/javascript"></script>
<script src="js/plugins/jquery.periodic.js" type="text/javascript"></script> <script src="js/plugins/jquery.periodic.js" type="text/javascript"></script>
<script src="js/plugins/jquery.scrollTo-1.4.2-min.js" type="text/javascript"></script> <script src="js/plugins/jquery.scrollTo-1.4.2-min.js" type="text/javascript"></script>
@ -54,23 +55,23 @@
<a href="#" class="button" id="action_IncreaseWidth" title="Increase Width"><img src="images/plus_8x8.png" /></a> <a href="#" class="button" id="action_IncreaseWidth" title="Increase Width"><img src="images/plus_8x8.png" /></a>
</div> </div>
<div class="subactions floatleft"> <div class="subactions floatleft">
<div id="songactions"> <div id="songActions">
<a href="#" class="button" id="action_SelectAll" title="Select All">All</a> <a href="#" class="button disabled" id="action_SelectAll" title="Select All">All</a>
<a href="#" class="button" id="action_SelectNone" title="Select None">None</a> <a href="#" class="button disabled" id="action_SelectNone" title="Select None">None</a>
<a href="#" class="button" id="action_AddToPlaylist" title="Add Selected To Playlist">+ Playlist</a> <a href="#" class="button disabled" id="action_AddToPlaylist" title="Add Selected To Playlist">+ Playlist</a>
<div id="submenu_AddToPlaylist" class="submenu shadow" style="display: none;"></div> <div id="submenu_AddToPlaylist" class="submenu shadow" style="display: none;"></div>
<a href="#" class="button" id="action_AddToCurrent" title="Add Selected To Current Playlist">+ Current</a> <a href="#" class="button disabled" id="action_AddToCurrent" title="Add Selected To Current Playlist">+ Current</a>
<a href="#" class="button" id="action_AddAllToCurrent" title="Add All to Current Playlist">+All</a> <a href="#" class="button disabled" id="action_AddAllToCurrent" title="Add All to Current Playlist">+All</a>
<a href="#" class="button" id="action_PlayAlbum" title="Play Album"><img src="images/play_gl_6x8.png" /></a> <a href="#" class="button disabled" id="action_PlayAlbum" title="Play Album"><img src="images/play_gl_6x8.png" /></a>
</div> </div>
<input type="text" id="Search" class="medium" /> <input type="text" id="Search" class="medium" title="Wildcards (*) supported"/>
<select id="SearchType" name="SearchType"> <select id="SearchType" name="SearchType">
<option value="song">Song</option> <option value="song">Song</option>
<option value="album">Album</option> <option value="album">Album</option>
</select> </select>
<a href="#" class="button" id="action_Search" title="Search"><img class="pad" src="images/magnifying_glass_alt_12x12.png" /></a> <a href="#" class="button" id="action_Search" title="Search"><img class="pad" src="images/magnifying_glass_alt_12x12.png" /></a>
</div> </div>
<div id="Albums" class="lgsection floatleft"> <div id="Albums" class="section lgsection floatleft">
<div class="loading"></div> <div class="loading"></div>
<div id="Artists" class="smsection floatleft" tabindex="0"> <div id="Artists" class="smsection floatleft" tabindex="0">
<div class="padder"> <div class="padder">
@ -91,11 +92,11 @@
<div id="BottomContainer"><ul id="BottomIndex"></ul></div> <div id="BottomContainer"><ul id="BottomIndex"></ul></div>
</div> </div>
<table id="AlbumContainer" class="simplelist songlist noselect" cellspacing="1"> <table id="AlbumContainer" class="simplelist songlist noselect" cellspacing="1">
<thead id="AlbumHeader"></thead> <thead></thead>
<tbody id="AlbumRows"></tbody> <tbody></tbody>
</table> </table>
</div> </div>
<div id="status_Library" class="status alignleft" data-type="" data-offset=""><img src="images/arrow_left_gl_8x8.png" /> <a id="action_PreviousAlbumList" class="previous" href="#">Previous</a> | <a id="action_NextAlbumList" class="next" href="#">Next</a> <img src="images/arrow_right_gl_8x8.png" /></div>
</div> </div>
<div id="tabCurrent" class="tabcontent"> <div id="tabCurrent" class="tabcontent">
<div class="actions floatleft"> <div class="actions floatleft">
@ -103,19 +104,21 @@
<a href="#" class="button" id="action_Empty" title="Remove All">Empty</a> <a href="#" class="button" id="action_Empty" title="Remove All">Empty</a>
</div> </div>
<div class="subactions floatleft"> <div class="subactions floatleft">
<a href="#" class="button" id="action_CurrentSelectAll" title="Select All">All</a> <div id="currentActions">
<a href="#" class="button" id="action_CurrentSelectNone" title="Select None">None</a> <a href="#" class="button disabled" id="action_CurrentSelectAll" title="Select All">All</a>
<a href="#" class="button" id="action_AddCurrentToPlaylist" title="Add Selected To Playlist">+ Playlist</a> <a href="#" class="button disabled" id="action_CurrentSelectNone" title="Select None">None</a>
<a href="#" class="button disabled" id="action_AddCurrentToPlaylist" title="Add Selected To Playlist">+ Playlist</a>
<div id="submenu_AddCurrentToPlaylist" class="submenu shadow" style="display: none;"></div> <div id="submenu_AddCurrentToPlaylist" class="submenu shadow" style="display: none;"></div>
<a href="#" class="button" id="action_AutoPilot" title="Autopilot"><img class="pad" src="images/steering_wheel_gd_12x12.png" /></a> <a href="#" class="button" id="action_AutoPilot" title="Autopilot"><img class="pad" src="images/steering_wheel_gd_12x12.png" /></a>
</div>
</div> </div>
<div id="CurrentPlaylist" class="fullsection floatleft noselect"> <div id="CurrentPlaylist" class="section fullsection floatleft noselect">
<table id="CurrentPlaylistContainer" class="simplelist songlist" cellspacing="1"> <table id="CurrentPlaylistContainer" class="simplelist songlist" cellspacing="1">
<thead></thead> <thead></thead>
<tbody></tbody> <tbody></tbody>
</table> </table>
</div> </div>
<div id="status"></div> <div id="status_Current" class="status">0 song(s), 00:00:00 total time</div>
</div> </div>
<div id="tabPlaylists" class="tabcontent"> <div id="tabPlaylists" class="tabcontent">
<div class="actions floatleft"> <div class="actions floatleft">
@ -129,7 +132,7 @@
<a href="#" class="button" id="action_RemoveSongs" title="Remove selected song(s) from playlist">Remove Song(s)</a> <a href="#" class="button" id="action_RemoveSongs" title="Remove selected song(s) from playlist">Remove Song(s)</a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<div id="Tracks" class="lgsection floatleft noselect"> <div id="Tracks" class="section lgsection floatleft noselect">
<div class="loading"></div> <div class="loading"></div>
<div id="Playlists" class="smsection floatleft noselect"> <div id="Playlists" class="smsection floatleft noselect">
<div class="padder"> <div class="padder">
@ -146,6 +149,7 @@
<tbody></tbody> <tbody></tbody>
</table> </table>
</div> </div>
<div id="status_Playlists" class="status">0 song(s), 00:00:00 total time</div>
</div> </div>
<div id="tabPodcasts" class="tabcontent"> <div id="tabPodcasts" class="tabcontent">
<div class="actions floatleft"> <div class="actions floatleft">
@ -154,7 +158,7 @@
<div class="subactions floatleft"> <div class="subactions floatleft">
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<div id="Podcasts" class="lgsection floatleft noselect"> <div id="Podcasts" class="section lgsection floatleft noselect">
<div class="loading"></div> <div class="loading"></div>
<div id="PodcastList" class="smsection floatleft noselect"> <div id="PodcastList" class="smsection floatleft noselect">
<div class="padder"> <div class="padder">
@ -167,6 +171,7 @@
<tbody></tbody> <tbody></tbody>
</table> </table>
</div> </div>
<div id="status_Podcasts" class="status">0 song(s), 00:00:00 total time</div>
</div> </div>
<div id="tabPreferences" class="tabcontent"> <div id="tabPreferences" class="tabcontent">
<div class="actions floatleft"> <div class="actions floatleft">
@ -174,7 +179,7 @@
<a href="#" class="button" id="SavePreferences" title="Save Preferences">Save</a> <a href="#" class="button" id="SavePreferences" title="Save Preferences">Save</a>
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<div class="lgsection floatleft"> <div class="section lgsection floatleft">
<div class="subsection floatleft"> <div class="subsection floatleft">
<h3 class="title">Login</h3> <h3 class="title">Login</h3>
<label for="Username">Username <span class="red">*</span></label><br /> <label for="Username">Username <span class="red">*</span></label><br />
@ -272,10 +277,15 @@
<span class="changes">- </span> <span class="changes">- </span>
</li> </li>
--> -->
<li class="log"><span class="version">10/15/2012 - 2.2.0</span>
<span class="changes">- Column sorting for all headers in all tables! (Thanks to <a href="https://github.com/joequery/Stupid-Table-Plugin" target="_blank">joequery</a>)</span>
<span class="changes">- Fancy Webkit styled scrollbars for those of you with browsers that don't suck (Works with Dark theme)</span>
<span class="changes">- Auto Albums feature Next & Previous links to page through results</span>
<span class="changes">- Forced to include permissions ("http://*/*" & "https://*/*"). Your Subsonic server can be at any URL. Will be asked to accept "Access your data on all websites".</span>
</li>
<li class="log"><span class="version">10/8/2012 - 2.1.5</span> <li class="log"><span class="version">10/8/2012 - 2.1.5</span>
<span class="changes">- Added song count and total time to Current Playlist</span> <span class="changes">- Added song count and total time to Current Playlist</span>
<span class="changes">- Migrated to version 2 of Chrome App manifest.json</span> <span class="changes">- Migrated to version 2 of Chrome App manifest.json</span>
<span class="changes">- Added to manifest.json > "content_security_policy": "script-src 'self' https://*/; object-src 'self'"</span>
</li> </li>
<li class="log"><span class="version">10/7/2012 - 2.1.2</span> <li class="log"><span class="version">10/7/2012 - 2.1.2</span>
<span class="changes">- Current Playlist will stay focused on the current track (Thanks <a href="https://github.com/tsquillario/MiniSub/issues/42" target="_blank">Concept211</a>)</span> <span class="changes">- Current Playlist will stay focused on the current track (Thanks <a href="https://github.com/tsquillario/MiniSub/issues/42" target="_blank">Concept211</a>)</span>

View file

@ -10,6 +10,7 @@ var passwordenc;
var server; var server;
var smwidth; var smwidth;
var volume = 50; var volume = 50;
var currentVersion = '2.2.0';
function getCookie(value) { function getCookie(value) {
if ($.cookie(value)) { if ($.cookie(value)) {
@ -96,6 +97,9 @@ if (getCookie('password')) {
setCookie('passwordenc', 'enc:' + HexEncode(getCookie('password'))); setCookie('passwordenc', 'enc:' + HexEncode(getCookie('password')));
setCookie('password', null); setCookie('password', null);
} }
if (getCookie('Volume')) {
volume = parseInt(getCookie('Volume'));
}
var version = '1.6.0'; var version = '1.6.0';
function loadTabContent(tab) { function loadTabContent(tab) {
@ -113,19 +117,28 @@ function loadTabContent(tab) {
case '#tabCurrent': case '#tabCurrent':
if (debug) { console.log("TAG CURRENT"); } if (debug) { console.log("TAG CURRENT"); }
var header = generateSongHeaderHTML(); var header = generateSongHeaderHTML();
$("#CurrentPlaylistContainer thead").html(header); $('#CurrentPlaylistContainer thead').html(header);
window.location.hash = '#tabCurrent'; var count = $('#CurrentPlaylistContainer tbody tr.song').size();
updateStatus(countCurrentPlaylist('#CurrentPlaylistContainer')); updateStatus('#status_Current', countCurrentPlaylist('#CurrentPlaylistContainer'));
if (count > 0) {
$('#currentActions a.button').removeClass('disabled');
}
var songid = $('#CurrentPlaylistContainer tbody tr.playing').attr('childid');
if (songid !== undefined) {
$('#CurrentPlaylist').scrollTo($('#' + songid), 400);
}
break; break;
case '#tabPlaylists': case '#tabPlaylists':
if (debug) { console.log("TAG PLAYLIST"); } if (debug) { console.log("TAG PLAYLIST"); }
loadPlaylists(); loadPlaylists();
loadFolders(); loadFolders();
loadAutoPlaylists(); loadAutoPlaylists();
updateStatus('#status_Playlists', countCurrentPlaylist('#TrackContainer'));
break; break;
case '#tabPodcasts': case '#tabPodcasts':
if (debug) { console.log("TAG PODCAST"); } if (debug) { console.log("TAG PODCAST"); }
loadPodcasts(); loadPodcasts();
updateStatus('#status_Podcasts', countCurrentPlaylist('#PodcastContainer'));
break; break;
case '#tabVideos': case '#tabVideos':
if (debug) { console.log("TAG VIDEOS"); } if (debug) { console.log("TAG VIDEOS"); }

View file

@ -81,7 +81,7 @@ function loadArtists(id, refresh) {
} else { } else {
indexes[0] = data["subsonic-response"].indexes.child; indexes[0] = data["subsonic-response"].indexes.child;
} }
var appendto = '#AlbumRows'; var appendto = '#AlbumContainer tbody';
$(appendto).empty(); $(appendto).empty();
$.each(indexes, function (i, child) { $.each(indexes, function (i, child) {
if (i % 2 === 0) { if (i % 2 === 0) {
@ -102,8 +102,6 @@ function loadArtists(id, refresh) {
var errorcode = data["subsonic-response"].error.code; var errorcode = data["subsonic-response"].error.code;
var errormsg = data["subsonic-response"].error.message; var errormsg = data["subsonic-response"].error.message;
alert('Status: ' + error + ', Code: ' + errorcode + ', Message: ' + errormsg); alert('Status: ' + error + ', Code: ' + errorcode + ', Message: ' + errormsg);
//var errorhtml = '<li class=\"item\"><span>' + error + '</span></li>';
//$(errorhtml).appendTo("#IndexList");
} }
} }
}); });
@ -187,13 +185,13 @@ function getAlbums(id, action, appendto) {
timeout: 10000, timeout: 10000,
success: function (data) { success: function (data) {
if (action == '') { if (action == '') {
$('#AlbumRows').empty(); $('#AlbumContainer tbody').empty();
} }
if (action === 'autoplay') { if (action === 'autoplay') {
$('#CurrentPlaylistContainer tbody').empty(); $('#CurrentPlaylistContainer tbody').empty();
} }
if (action == 'link') { if (action == 'link') {
$('#AlbumRows').empty(); $('#AlbumContainer tbody').empty();
$('#action_tabLibrary').trigger('click'); $('#action_tabLibrary').trigger('click');
} }
if (data["subsonic-response"].directory.child !== undefined) { if (data["subsonic-response"].directory.child !== undefined) {
@ -216,18 +214,21 @@ function getAlbums(id, action, appendto) {
} }
if (child.isDir == true) { isDir = true; } if (child.isDir == true) { isDir = true; }
var html = generateRowHTML(child, appendto, rowcolor); var html = generateRowHTML(child, appendto, rowcolor);
$(html).appendTo(appendto); $(html).appendTo(appendto).hide().fadeIn('fast');
}); });
toggleAlbumListNextPrev('#status_Library', false, '', '');
if (appendto == '#CurrentPlaylistContainer') { if (appendto == '#CurrentPlaylistContainer') {
updateMessage(children.length + ' Song(s) Added'); updateMessage(children.length + ' Song(s) Added');
} }
if (appendto == '#AlbumRows' && isDir == true) { if (appendto == '#AlbumContainer tbody' && isDir == true) {
header = generateAlbumHeaderHTML(); header = generateAlbumHeaderHTML();
$('#songActions a.button').addClass('disabled');
} }
if (appendto == '#AlbumRows' && isDir == false) { if (appendto == '#AlbumContainer tbody' && isDir == false) {
header = generateSongHeaderHTML(); header = generateSongHeaderHTML();
$('#songActions a.button').removeClass('disabled');
} }
$("#AlbumHeader").html(header); $("#AlbumContainer thead").html(header);
if (action == 'autoplay') { if (action == 'autoplay') {
autoPlay(); autoPlay();
} }
@ -235,23 +236,28 @@ function getAlbums(id, action, appendto) {
} }
}); });
} }
function getAlbumListBy(id) { function getAlbumListBy(id, offset) {
var size; var size, url;
if (getCookie('AutoAlbumSize') === null) { if (getCookie('AutoAlbumSize')) {
size = 15;
} else {
size = getCookie('AutoAlbumSize'); size = getCookie('AutoAlbumSize');
} else {
size = 15;
}
if (offset > 0) {
url = baseURL + '/getAlbumList.view?u=' + username + '&p=' + password + '&v=' + version + '&c=' + applicationName + '&f=json&size=' + size + '&type=' + id + '&offset=' + offset
} else {
url = baseURL + '/getAlbumList.view?u=' + username + '&p=' + password + '&v=' + version + '&c=' + applicationName + '&f=json&size=' + size + '&type=' + id
} }
$.ajax({ $.ajax({
url: baseURL + '/getAlbumList.view?u=' + username + '&p=' + password + '&v=' + version + '&c=' + applicationName + '&f=json&size=' + size + '&type=' + id, url: url,
method: 'GET', method: 'GET',
dataType: 'json', dataType: 'json',
timeout: 10000, timeout: 10000,
success: function (data) { success: function (data) {
if (data["subsonic-response"].albumList.album !== undefined) { if (data["subsonic-response"].albumList.album !== undefined) {
$("#AlbumRows").empty(); $("#AlbumContainer tbody").empty();
var header = generateAlbumHeaderHTML(); var header = generateAlbumHeaderHTML();
$("#AlbumHeader").html(header); $("#AlbumContainer thead").html(header);
// There is a bug in the API that doesn't return a JSON array for one artist // There is a bug in the API that doesn't return a JSON array for one artist
var albums = []; var albums = [];
if (data["subsonic-response"].albumList.album.length > 0) { if (data["subsonic-response"].albumList.album.length > 0) {
@ -274,14 +280,34 @@ function getAlbumListBy(id) {
if (album.isDir === true) { if (album.isDir === true) {
albumhtml = generateAlbumHTML(rowcolor, album.id, album.parent, album.coverArt, album.title, album.artist, album.userRating, starred); albumhtml = generateAlbumHTML(rowcolor, album.id, album.parent, album.coverArt, album.title, album.artist, album.userRating, starred);
} }
$(albumhtml).appendTo("#AlbumRows"); $(albumhtml).appendTo("#AlbumContainer tbody").hide().fadeIn('fast');
}); });
$('#songActions a.button').addClass('disabled');
toggleAlbumListNextPrev('#status_Library', true, id, offset);
} else { } else {
$('#AlbumRows').empty(); $('#AlbumContainer tbody').empty();
} }
} }
}); });
} }
function toggleAlbumListNextPrev(el, on, type, offset) {
if (el != '') {
if (on) {
$(el).addClass('on');
$('#status_Library').data('type', type);
if (offset === undefined) {
$('#status_Library').data('offset', '0');
} else {
$('#status_Library').data('offset', offset);
}
} else {
$(el).removeClass('on');
$(el).stop().fadeOut();
$('#status_Library').data('type', '');
$('#status_Library').data('offset', '0');
}
}
}
function getRandomSongList(action, appendto, genre, folder) { function getRandomSongList(action, appendto, genre, folder) {
var size, gstring; var size, gstring;
gstring = ''; gstring = '';
@ -342,7 +368,7 @@ function getRandomSongList(action, appendto, genre, folder) {
$(html).appendTo(appendto); $(html).appendTo(appendto);
}); });
if (appendto === '#TrackContainer tbody') { if (appendto === '#TrackContainer tbody') {
updateMessage(countCurrentPlaylist('#TrackContainer')); updateStatus('#status_Playlists', countCurrentPlaylist('#TrackContainer'));
} }
if (appendto === '#CurrentPlaylistContainer tbody') { if (appendto === '#CurrentPlaylistContainer tbody') {
updateMessage(items.length + ' Song(s) Added'); updateMessage(items.length + ' Song(s) Added');
@ -443,7 +469,7 @@ function getStarred(action, appendto, type) {
$(html).appendTo(appendto); $(html).appendTo(appendto);
}); });
if (appendto == '#TrackContainer tbody') { if (appendto == '#TrackContainer tbody') {
updateMessage(countCurrentPlaylist('#TrackContainer')); updateStatus('#status_Playlists', countCurrentPlaylist('#TrackContainer'));
} }
if (appendto == '#CurrentPlaylistContainer tbody') { if (appendto == '#CurrentPlaylistContainer tbody') {
updateMessage(items.length + ' Song(s) Added'); updateMessage(items.length + ' Song(s) Added');
@ -526,31 +552,32 @@ function search(type, query) {
dataType: 'json', dataType: 'json',
timeout: 10000, timeout: 10000,
success: function (data) { success: function (data) {
$("#AlbumContainer tbody").empty();
if (data["subsonic-response"].searchResult2 !== "") { if (data["subsonic-response"].searchResult2 !== "") {
$("#AlbumRows").empty();
var header; var header;
var children = []; var children = [];
if (type === 'song') { if (type === 'song') {
header = generateSongHeaderHTML();
if (data["subsonic-response"].searchResult2.song !== undefined) { if (data["subsonic-response"].searchResult2.song !== undefined) {
header = generateSongHeaderHTML();
if (data["subsonic-response"].searchResult2.song.length > 0) { if (data["subsonic-response"].searchResult2.song.length > 0) {
children = data["subsonic-response"].searchResult2.song; children = data["subsonic-response"].searchResult2.song;
} else { } else {
children[0] = data["subsonic-response"].searchResult2.song; children[0] = data["subsonic-response"].searchResult2.song;
} }
$("#AlbumContainer thead").html(header);
} }
} }
if (type === 'album') { if (type === 'album') {
header = generateAlbumHeaderHTML();
if (data["subsonic-response"].searchResult2.album !== undefined) { if (data["subsonic-response"].searchResult2.album !== undefined) {
header = generateAlbumHeaderHTML();
if (data["subsonic-response"].searchResult2.album.length > 0) { if (data["subsonic-response"].searchResult2.album.length > 0) {
children = data["subsonic-response"].searchResult2.album; children = data["subsonic-response"].searchResult2.album;
} else { } else {
children[0] = data["subsonic-response"].searchResult2.album; children[0] = data["subsonic-response"].searchResult2.album;
} }
$("#AlbumContainer thead").html(header);
} }
} }
$("#AlbumHeader").html(header);
$.each(children, function (i, child) { $.each(children, function (i, child) {
if (i % 2 === 0) { if (i % 2 === 0) {
rowcolor = 'even'; rowcolor = 'even';
@ -569,7 +596,7 @@ function search(type, query) {
if (child.duration !== undefined) { duration = child.duration; } else { duration = ''; } if (child.duration !== undefined) { duration = child.duration; } else { duration = ''; }
albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, '', child.artist, child.album, child.coverArt, child.userRating, starred, duration); albumhtml = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, '', child.artist, child.album, child.coverArt, child.userRating, starred, duration);
} }
$(albumhtml).appendTo("#AlbumRows"); $(albumhtml).appendTo("#AlbumContainer tbody");
}); });
} }
} }
@ -648,6 +675,84 @@ function loadPlaylists(refresh) {
}); });
} }
} }
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?u=' + username + '&p=' + password,
dataType: 'json',
timeout: 10000,
data: { v: version, c: applicationName, f: "json", playlistId: playlistid, songId: songs },
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=' + password + '&v=' + version + '&c=' + applicationName + '&f=json&id=' + id,
method: 'GET',
dataType: 'json',
timeout: 10000,
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 = [];
var playlist = data["subsonic-response"].playlist;
if (playlist.entry.length > 0) {
children = playlist.entry;
} else {
children[0] = playlist.entry;
}
var rowcolor;
var html;
var count = children.length;
$.each(children, function (i, child) {
if (i % 2 === 0) {
rowcolor = 'even';
} else {
rowcolor = 'odd';
}
var track, starred, duration;
if (child.starred !== undefined) { starred = true; } else { starred = false; }
if (child.track === undefined) { track = "&nbsp;"; } else { track = child.track; }
if (child.duration !== undefined) { duration = child.duration; } else { duration = ''; }
html = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, '', child.artist, child.album, child.coverArt, child.userRating, starred, duration);
$(html).appendTo(appendto);
});
if (appendto === '#TrackContainer tbody') {
updateStatus('#status_Playlists', countCurrentPlaylist('#TrackContainer'));
}
if (appendto === '#CurrentPlaylistContainer tbody') {
updateMessage(children.length + ' Song(s) Added');
}
if (action === 'autoplay') {
autoPlay();
}
} else {
if (appendto === '#TrackContainer tbody') {
$(appendto).empty();
}
}
}
});
}
function loadPlaylistsForMenu(menu) { function loadPlaylistsForMenu(menu) {
$('#' + menu).empty(); $('#' + menu).empty();
$.ajax({ $.ajax({
@ -814,6 +919,7 @@ function addToCurrent(addAll) {
$(this).clone().appendTo('#CurrentPlaylistContainer tbody'); $(this).clone().appendTo('#CurrentPlaylistContainer tbody');
}); });
} }
$('#CurrentPlaylistContainer tbody tr.song').removeClass('selected');
updateMessage(count + ' Song(s) Added'); updateMessage(count + ' Song(s) Added');
} }
} }
@ -870,6 +976,25 @@ function loadCurrentPlaylist() {
if (debug) { console.log('HTML5::loadStorage not supported on your browser' + html.length + ' characters'); } if (debug) { console.log('HTML5::loadStorage not supported on your browser' + html.length + ' characters'); }
} }
} }
function saveTrackPosition() {
var el = $('#songdetails_song');
var songid = el.attr('childid');
if (songid !== undefined) {
var albumid = el.attr('parentid');
var sm = soundManager.getSoundById('audio');
var position = sm.position;
if (position != null && position >= 5000) {
var currentSong = {
songid: songid,
albumid: albumid,
position: position
};
setCookie('CurrentSong', JSON.stringify(currentSong));
saveCurrentPlaylist();
}
}
if (debug) { console.log('Saving Track Position: songid:' + songid + ', albumid:' + albumid + ', position:' + position); }
}
function downloadItem(id, type) { function downloadItem(id, type) {
var url; var url;
if (type == 'item' && id) { if (type == 'item' && id) {
@ -883,84 +1008,7 @@ function downloadItem(id, type) {
window.location = url; 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?u=' + username + '&p=' + password,
dataType: 'json',
timeout: 10000,
data: { v: version, c: applicationName, f: "json", playlistId: playlistid, songId: songs },
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=' + password + '&v=' + version + '&c=' + applicationName + '&f=json&id=' + id,
method: 'GET',
dataType: 'json',
timeout: 10000,
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 = [];
var playlist = data["subsonic-response"].playlist;
if (playlist.entry.length > 0) {
children = playlist.entry;
} else {
children[0] = playlist.entry;
}
var rowcolor;
var html;
var count = children.length;
$.each(children, function (i, child) {
if (i % 2 === 0) {
rowcolor = 'even';
} else {
rowcolor = 'odd';
}
var track, starred, duration;
if (child.starred !== undefined) { starred = true; } else { starred = false; }
if (child.track === undefined) { track = "&nbsp;"; } else { track = child.track; }
if (child.duration !== undefined) { duration = child.duration; } else { duration = ''; }
html = generateSongHTML(rowcolor, child.id, child.parent, track, child.title, '', child.artist, child.album, child.coverArt, child.userRating, starred, duration);
$(html).appendTo(appendto);
});
if (appendto === '#TrackContainer tbody') {
updateMessage(countCurrentPlaylist('#TrackContainer'));
}
if (appendto === '#CurrentPlaylistContainer tbody') {
updateMessage(children.length + ' Song(s) Added');
}
if (action === 'autoplay') {
autoPlay();
}
} else {
if (appendto === '#TrackContainer tbody') {
$(appendto).empty();
}
}
}
});
}
function loadPodcasts(refresh) { function loadPodcasts(refresh) {
if (debug) { console.log("LOAD PODCASTS"); } if (debug) { console.log("LOAD PODCASTS"); }
@ -1040,7 +1088,6 @@ function getPodcast(id, action, appendto) {
var count = 0; var count = 0;
$.each(children, function (i, child) { $.each(children, function (i, child) {
if (child.status == "skipped") return; // Skip podcasts that are not yet downloaded if (child.status == "skipped") return; // Skip podcasts that are not yet downloaded
if (i % 2 === 0) { if (i % 2 === 0) {
rowcolor = 'even'; rowcolor = 'even';
} else { } else {
@ -1050,16 +1097,17 @@ function getPodcast(id, action, appendto) {
var description = 'Published: ' + date + '\n\n'; var description = 'Published: ' + date + '\n\n';
description += child.description; description += child.description;
var starred, duration; var starred, duration, publishdate;
if (child.starred !== undefined) { starred = true; } else { starred = false; } if (child.starred !== undefined) { starred = true; } else { starred = false; }
if (child.duration !== undefined) { duration = child.duration; } else { duration = ''; } if (child.duration !== undefined) { duration = child.duration; } else { duration = ''; }
if (child.publishDate !== undefined) { publishdate = child.publishDate.substring(0, child.publishDate.indexOf(" ")); } else { publishdate = ''; }
var time = secondsToTime(child.duration); var time = secondsToTime(child.duration);
html = generateSongHTML(rowcolor, child.streamId, child.parent, child.track, child.title, description, child.artist, child.album, child.coverArt, child.userRating, starred, duration); html = generateSongHTML(rowcolor, child.streamId, child.parent, publishdate, child.title, description, child.artist, child.album, child.coverArt, child.userRating, starred, duration);
$(html).appendTo(appendto); $(html).appendTo(appendto);
count++; count++;
}); });
if (appendto === '#PodcastContainer tbody') { if (appendto === '#PodcastContainer tbody') {
updateMessage(count + ' Song(s)'); updateStatus('#status_Podcasts', countCurrentPlaylist('#PodcastContainer'));
} }
if (appendto === '#CurrentPlaylistContainer tbody') { if (appendto === '#CurrentPlaylistContainer tbody') {
updateMessage(count + ' Song(s) Added'); updateMessage(count + ' Song(s) Added');

View file

@ -14,7 +14,7 @@ function generateRowHTML(child, appendto, rowcolor) {
} }
function generateAlbumHeaderHTML() { function generateAlbumHeaderHTML() {
var html; var html;
html = '<tr><th></th><th></th><th>Album</th><th>Artist</th></tr>'; html = '<tr><th></th><th></th><th class=\"type-string\">Album</th><th class=\"type-string\">Artist</th></tr>';
return html; return html;
} }
function generateAlbumHTML(rowcolor, childid, parentid, coverart, title, artist, rating, starred) { function generateAlbumHTML(rowcolor, childid, parentid, coverart, title, artist, rating, starred) {
@ -41,7 +41,7 @@ function generateAlbumHTML(rowcolor, childid, parentid, coverart, title, artist,
} }
function generateSongHeaderHTML() { function generateSongHeaderHTML() {
var html; var html;
html = '<tr><th></th><th>Track</th><th>Title</th><th>Artist</th><th>Album</th><th class=\"alignright\">Time</th></tr>'; html = '<tr><th></th><th class=\"type-int\">Track</th><th class=\"type-string\">Title</th><th class=\"type-string\">Artist</th><th class=\"type-string\">Album</th><th class=\"alignright\">Time</th></tr>';
return html; return html;
} }
function generateSongHTML(rowcolor, childid, parentid, track, title, description, artist, album, coverart, rating, starred, duration) { function generateSongHTML(rowcolor, childid, parentid, track, title, description, artist, album, coverart, rating, starred, duration) {
@ -76,11 +76,12 @@ function generateSongHTML(rowcolor, childid, parentid, track, title, description
} else { } else {
coverartSrc = baseURL + '/getCoverArt.view?v=' + version + '&c=' + applicationName + '&f=json&size=25&id=' + coverart; coverartSrc = baseURL + '/getCoverArt.view?v=' + version + '&c=' + applicationName + '&f=json&size=25&id=' + coverart;
} }
html += '<td class=\"album\"><a href="#" class=\"albumlink\"><img src=\"' + coverartSrc + '\" />' + album + '</a></td>'; html += '<td class=\"album\" data-order-by=\"' + album + '\"><a href="#" class=\"albumlink\"><img src=\"' + coverartSrc + '\" />' + album + '</a></td>';
html += '<td class=\"time\">' + time + '</td>'; html += '<td class=\"time\">' + time + '</td>';
html += '</tr>'; html += '</tr>';
return html; return html;
} }
// Depreciated: 10/17/2012
function refreshRowColor(el) { function refreshRowColor(el) {
$.each($(el + ' tr.song'), function (i) { $.each($(el + ' tr.song'), function (i) {
$(this).removeClass('even odd'); $(this).removeClass('even odd');

View file

@ -19,7 +19,7 @@ function playSong(el, songid, albumid, position, loadonly) {
} }
$.each(children, function (i, child) { $.each(children, function (i, child) {
if (child.id == songid) { if (child.id == songid) {
title = child.title; title = child.title.toString();
artist = child.artist; artist = child.artist;
album = child.album; album = child.album;
coverart = child.coverArt; coverart = child.coverArt;
@ -67,6 +67,7 @@ function playSong(el, songid, albumid, position, loadonly) {
url: baseURL + '/stream.view?u=' + username + '&p=' + password + '&v=' + version + '&c=' + applicationName + '&id=' + songid + '&salt=' + salt, url: baseURL + '/stream.view?u=' + username + '&p=' + password + '&v=' + version + '&c=' + applicationName + '&id=' + songid + '&salt=' + salt,
stream: true, stream: true,
type: 'audio/mp3', type: 'audio/mp3',
multiShot: false,
whileloading: function () { whileloading: function () {
//if (debug) { console.log('loaded:' + this.bytesLoaded + ' total:' + this.bytesTotal); } //if (debug) { console.log('loaded:' + this.bytesLoaded + ' total:' + this.bytesTotal); }
var percent = this.bytesLoaded / this.bytesTotal; var percent = this.bytesLoaded / this.bytesTotal;
@ -105,9 +106,8 @@ function playSong(el, songid, albumid, position, loadonly) {
scrubber.click(function (e) { scrubber.click(function (e) {
var x = (e.pageX - this.offsetLeft) / scrubber.width(); var x = (e.pageX - this.offsetLeft) / scrubber.width();
var position = Math.round(dp * 1000 * x); var position = Math.round(dp * 1000 * x);
soundManager.play('audio', { var s = soundManager.getSoundById('audio');
position: position s.setPosition(position);
});
}); });
scrubber.mouseover(function (e) { scrubber.mouseover(function (e) {
$('.audiojs .scrubber').stop().animate({ height: '8px' }); $('.audiojs .scrubber').stop().animate({ height: '8px' });
@ -141,10 +141,11 @@ function playSong(el, songid, albumid, position, loadonly) {
}); });
if (position == 0) { if (position == 0) {
soundManager.play('audio'); soundManager.play('audio');
soundManager.setVolume('audio', volume);
} else { } else {
var p = position; var p = position;
//soundManager.play('audio', { position: p });
seekAndPlay('audio', p); seekAndPlay('audio', p);
soundManager.setVolume('audio', volume);
} }
var submenu = $('div#submenu_CurrentPlaylist'); var submenu = $('div#submenu_CurrentPlaylist');
if (submenu.is(":visible")) { if (submenu.is(":visible")) {
@ -175,23 +176,23 @@ function playSong(el, songid, albumid, position, loadonly) {
} }
function seekAndPlay(soundID, soundPosition) { function seekAndPlay(soundID, soundPosition) {
var s = soundManager.getSoundById(soundID); var s = soundManager.getSoundById(soundID);
if (!s) { if (s) {
return false; s.unload();
} if (s.readyState === 0) { // hasn't started loading yet...
if (s.readyState === 0) { // hasn't started loading yet... // load the whole sound, and play when it's done
// load the whole sound, and play when it's done s.load({
s.load({ onload: function () {
onload: function () { this.play({
this.play({ position: soundPosition
position: soundPosition });
}); }
} });
}); } else if (s.readyState === 3) {
} else if (s.readyState === 3) { // sound has already loaded, ready to go
// sound has already loaded, ready to go s.play({
s.play({ position: soundPosition
position: soundPosition });
}); }
} }
} }
function scrobbleSong(submission) { function scrobbleSong(submission) {
@ -319,23 +320,4 @@ function nextPlay() {
} else { } else {
//song = $('#CurrentPlaylistContainer tr.playing').next(); //song = $('#CurrentPlaylistContainer tr.playing').next();
} }
}
function saveTrackPosition() {
var el = $('#songdetails_song');
var songid = el.attr('childid');
if (songid !== undefined) {
var albumid = el.attr('parentid');
var sm = soundManager.getSoundById('audio');
var position = sm.position;
if (position != null && position >= 5000) {
var currentSong = {
songid: songid,
albumid: albumid,
position: position
};
setCookie('CurrentSong', JSON.stringify(currentSong));
saveCurrentPlaylist();
}
}
if (debug) { console.log('Saving Track Position: songid:' + songid + ', albumid:' + albumid + ', position:' + position); }
} }

View file

@ -112,12 +112,15 @@ function updateMessage(msg) {
msgIndex++; msgIndex++;
} }
} }
function updateStatus(msg) { function updateStatus(el, msg) {
$('#status').html(msg); if (msg == '') {
if ($('#tabLibrary').not(':visible')) { $(el).html('0 song(s), 00:00:00 total time');
if ($('#status').html() != '') { } else {
$('#status').fadeIn(); $(el).html(msg);
} }
if ($(el).html() != '') {
$(el).addClass('on');
$(el).fadeIn();
} }
} }
// Convert to unicode support // Convert to unicode support
@ -254,6 +257,21 @@ function checkVersion(runningVersion, minimumVersion) {
return false; return false;
} }
} }
function checkVersionNewer(runningVersion, newVersion) {
if (runningVersion.major < newVersion.major) {
return true;
} else {
if (runningVersion.minor < newVersion.minor) {
return true;
} else {
if (runningVersion.patch < newVersion.patch) {
return true;
} else {
return false;
}
}
}
}
function switchTheme(theme) { function switchTheme(theme) {
switch (theme) { switch (theme) {
case 'dark': case 'dark':

View file

@ -0,0 +1,141 @@
// Stupid jQuery table plugin.
// Call on a table
// sortFns: Sort functions for your datatypes.
(function ($) {
$.fn.stupidtable = function (sortFns) {
var table = this; sortFns = sortFns || {};
// ==================================================== //
// Utility functions //
// ==================================================== //
// Merge sort functions with some default sort functions.
sortFns = $.extend({}, {
"int": function (a, b) { return parseInt(a, 10) - parseInt(b, 10); },
"float": function (a, b) { return parseFloat(a) - parseFloat(b); },
"string": function (a, b) { if (a < b) return -1; if (a > b) return +1; return 0; }
}, sortFns);
// Array comparison. See http://stackoverflow.com/a/8618383
var arrays_equal = function (a, b) { return !!a && !!b && !(a < b || b < a); }
// Return the resulting indexes of a sort so we can apply
// this result elsewhere. This returns an array of index numbers.
// return[0] = x means "arr's 0th element is now at x"
var sort_map = function (arr, sort_function) {
var sorted = arr.slice(0).sort(sort_function);
var map = [];
var index = 0;
for (var i = 0; i < arr.length; i++) {
index = $.inArray(arr[i], sorted);
// If this index is already in the map, look for the next index.
// This handles the case of duplicate entries.
while ($.inArray(index, map) != -1) {
index++;
}
map.push(index);
}
return map;
}
// Apply a sort map to the array.
var apply_sort_map = function (arr, map) {
var clone = arr.slice(0);
for (var i = 0; i < map.length; i++) {
newIndex = map[i];
clone[newIndex] = arr[i];
}
return clone;
}
// Returns true if array is sorted, false otherwise.
// Checks for both ascending and descending
var is_sorted_array = function (arr, sort_function) {
var clone = arr.slice(0);
var reversed = arr.slice(0).reverse();
var sorted = arr.slice(0).sort(sort_function);
// Check if the array is sorted in either direction.
return arrays_equal(clone, sorted) || arrays_equal(reversed, sorted);
}
// ==================================================== //
// Begin execution! //
// ==================================================== //
// Do sorting when THs are clicked
table.delegate("th", "click", function () {
var trs = table.find("tbody tr");
var i = $(this).index();
var classes = $(this).attr("class");
var type = null;
var sort = {
asc: 'ascending',
desc: 'descending'
};
var direction = sort.asc;
var total = trs.length;
if (total > 0) {
if (classes) {
classes = classes.split(/\s+/);
for (var j = 0; j < classes.length; j++) {
if (classes[j].search("type-") != -1) {
type = classes[j];
break;
}
}
if (type) {
type = type.split('-')[1];
}
}
if (type) {
table.find('th').removeClass('sorted');
var sortMethod = sortFns[type];
// Gather the elements for this column
column = [];
// Push either the value of the 'data-order-by' attribute if specified
// or just the text() value in this column to column[] for comparison.
trs.each(function (index, tr) {
var e = $(tr).children().eq(i);
var order_by = e.attr('data-order-by') || e.text();
column.push(order_by);
});
// If the column is already sorted, just reverse the order. The sort
// map is just reversing the indexes.
if (is_sorted_array(column, sortMethod)) {
if ($(this).hasClass(sort.desc)) {
direction = sort.asc;
} else {
direction = sort.desc
}
table.find('th').removeClass(sort.asc + ' ' + sort.desc);
column.reverse();
var theMap = [];
for (var i = column.length - 1; i >= 0; i--) {
theMap.push(i);
}
}
else {
direction = sort.asc;
// Get a sort map and apply to all rows
theMap = sort_map(column, sortMethod);
}
var sortedTRs = $(apply_sort_map(trs, theMap));
// Replace the content of tbody with the sortedTRs. Strangely (and
// conveniently!) enough, .append accomplishes this for us.
table.find("tbody").append(sortedTRs);
$(this).addClass('sorted');
$(this).addClass(direction);
}
}
});
}
})(jQuery);

View file

@ -63,7 +63,7 @@ function resizeContent() {
} }
} }
var tabwidth = $('.tabcontent').width(); var tabwidth = $('.tabcontent').width();
$('#AlbumContainer, #TrackContainer, #PodcastContainer, #CurrentPlaylistContainer').css({ 'width': (tabwidth - smwidth - 40) + 'px' }); $('#AlbumContainer, #TrackContainer, #PodcastContainer, #CurrentPlaylistContainer').css({ 'width': (tabwidth - smwidth - 45) + 'px' });
$('#CurrentPlaylistContainer').css({ 'width': (tabwidth - 30) + 'px' }); $('#CurrentPlaylistContainer').css({ 'width': (tabwidth - 30) + 'px' });
$('#player').css({ 'width': tabwidth + 'px' }); $('#player').css({ 'width': tabwidth + 'px' });
} }
@ -78,6 +78,6 @@ function resizeSMSection(x) {
$('#BottomContainer').css({ 'width': (newsmwidth - 23) + 'px' }); $('#BottomContainer').css({ 'width': (newsmwidth - 23) + 'px' });
setCookie('defaultsmwidth', newwidth); setCookie('defaultsmwidth', newwidth);
var ulwidth = newsmwidth + 6; var ulwidth = newsmwidth + 6;
$('#AlbumContainer, #TrackContainer, #PodcastContainer').css({ 'margin-left': ulwidth + 'px' }); $('#AlbumContainer, #TrackContainer, #PodcastContainer').css({ 'margin-left': (ulwidth + 15) + 'px' });
} }
} }

View file

@ -54,6 +54,22 @@
if (getCookie('AutoPilot')) { if (getCookie('AutoPilot')) {
setCookie('AutoPilot', null) setCookie('AutoPilot', null)
} }
// Version check
if (getCookie('CurrentVersion')) {
if (checkVersionNewer(parseVersionString(getCookie('CurrentVersion')), parseVersionString(currentVersion))) {
updateMessage('MiniSub updated to ' + currentVersion);
setCookie('CurrentVersion', currentVersion);
}
} else {
setCookie('CurrentVersion', currentVersion);
}
// Table Sorting
$('#CurrentPlaylistContainer').stupidtable();
$('#TrackContainer').stupidtable();
$('#PodcastContainer').stupidtable();
$('#AlbumContainer').stupidtable();
// Tabs // Tabs
$('.tabcontent').hide(); //Hide all content $('.tabcontent').hide(); //Hide all content
@ -91,12 +107,14 @@
// Tabs - Click Event // Tabs - Click Event
$("ul.tabs li a").click(function () { $("ul.tabs li a").click(function () {
$("ul.tabs li a").removeClass("active"); //Remove any "active" class var currentTab = window.location.hash;
$(this).addClass("active"); //Add "active" class to selected tab
$(".tabcontent").hide(); //Hide all tab content
var activeTab = $(this).attr("href"); //Find the href attribute value to identify the active tab + content var activeTab = $(this).attr("href"); //Find the href attribute value to identify the active tab + content
$(activeTab).fadeIn('fast'); //Fade in the active ID content if (currentTab != activeTab) {
$("ul.tabs li a").removeClass("active"); //Remove any "active" class
$(this).addClass("active"); //Add "active" class to selected tab
$(".tabcontent").hide(); //Hide all tab content
$(activeTab).fadeIn('fast'); //Fade in the active ID content
}
loadTabContent(activeTab); loadTabContent(activeTab);
}); });
@ -140,6 +158,7 @@
if (volume <= 100 && volume > 0 && source == '') { if (volume <= 100 && volume > 0 && source == '') {
volume += -10; volume += -10;
soundManager.setVolume('audio', volume); soundManager.setVolume('audio', volume);
setCookie('Volume', volume);
updateMessage('Volume: ' + volume + '%'); updateMessage('Volume: ' + volume + '%');
} }
} }
@ -147,6 +166,7 @@
if (volume < 100 && volume >= 0 && source == '') { if (volume < 100 && volume >= 0 && source == '') {
volume += 10; volume += 10;
soundManager.setVolume('audio', volume); soundManager.setVolume('audio', volume);
setCookie('Volume', volume);
updateMessage('Volume: ' + volume + '%'); updateMessage('Volume: ' + volume + '%');
} }
} }
@ -164,7 +184,7 @@
$('#AutoAlbumContainer li').removeClass('selected'); $('#AutoAlbumContainer li').removeClass('selected');
$('#ArtistContainer li').removeClass('selected'); $('#ArtistContainer li').removeClass('selected');
$(this).addClass('selected'); $(this).addClass('selected');
getAlbums($(this).attr("id"), '', '#AlbumRows'); getAlbums($(this).attr("id"), '', '#AlbumContainer tbody');
}); });
$('#BottomIndex li a').live('click', function () { $('#BottomIndex li a').live('click', function () {
var el = 'a[name = "index_' + $(this).text() + '"]'; var el = 'a[name = "index_' + $(this).text() + '"]';
@ -213,7 +233,14 @@
$('tr.album').live('click', function (e) { $('tr.album').live('click', function (e) {
var albumid = $(this).attr('childid'); var albumid = $(this).attr('childid');
var artistid = $(this).attr('parentid'); var artistid = $(this).attr('parentid');
getAlbums(albumid, '', '#AlbumRows'); getAlbums(albumid, '', '#AlbumContainer tbody');
return false;
});
$('tr.album').live('click', function (e) {
var albumid = $(this).attr('childid');
var artistid = $(this).attr('parentid');
getAlbums(albumid, '', '#AlbumContainer tbody');
return false; return false;
}); });
@ -292,7 +319,6 @@
$('table.songlist tr.song a.remove').live('click', function (event) { $('table.songlist tr.song a.remove').live('click', function (event) {
var track = $(this).parent().parent(); var track = $(this).parent().parent();
$(track).remove(); $(track).remove();
refreshRowColor('table.songlist');
return false; return false;
}); });
$('table.songlist tr.song a.rate').live('click', function (event) { $('table.songlist tr.song a.rate').live('click', function (event) {
@ -314,7 +340,9 @@
$('table.songlist tr.song a.albumlink').live('click', function (event) { $('table.songlist tr.song a.albumlink').live('click', function (event) {
var parentid = $(this).parent().parent().attr('parentid'); var parentid = $(this).parent().parent().attr('parentid');
if (parentid != '' && parentid !== undefined) { if (parentid != '' && parentid !== undefined) {
getAlbums(parentid, 'link', '#AlbumRows'); $('#AutoAlbumContainer li').removeClass('selected');
$('#ArtistContainer li').removeClass('selected');
getAlbums(parentid, 'link', '#AlbumContainer tbody');
} }
return false; return false;
}); });
@ -324,18 +352,20 @@
}); });
// Music Library Click Events // Music Library Click Events
$('a#action_AddToPlaylist').click(function () { $('#action_AddToPlaylist').click(function () {
var submenu = $('div#submenu_AddToPlaylist'); if (!$(this).hasClass('disabled')) {
if (submenu.is(":visible")) { var submenu = $('div#submenu_AddToPlaylist');
submenu.fadeOut(); if (submenu.is(":visible")) {
} else { submenu.fadeOut();
loadPlaylistsForMenu('submenu_AddToPlaylist'); } else {
//get the position of the placeholder element loadPlaylistsForMenu('submenu_AddToPlaylist');
pos = $(this).offset(); //get the position of the placeholder element
width = $(this).width(); pos = $(this).offset();
height = $(this).height(); width = $(this).width();
//show the menu directly over the placeholder height = $(this).height();
submenu.css({ "left": (pos.left) + "px", "top": (pos.top + height + 14) + "px" }).fadeIn(400); //show the menu directly over the placeholder
submenu.css({ "left": (pos.left) + "px", "top": (pos.top + height + 14) + "px" }).fadeIn(400);
}
} }
return false; return false;
}); });
@ -358,19 +388,25 @@
//setTimeout(function () { if (submenu_active == false) $('div.submenu').stop().fadeOut(); }, 400); //setTimeout(function () { if (submenu_active == false) $('div.submenu').stop().fadeOut(); }, 400);
}); });
$('a#action_AddToCurrent').click(function () { $('a#action_AddToCurrent').click(function () {
addToCurrent(false); if (!$(this).hasClass('disabled')) {
addToCurrent(false);
}
return false; return false;
}); });
$('a#action_AddAllToCurrent').click(function () { $('a#action_AddAllToCurrent').click(function () {
addToCurrent(true); if (!$(this).hasClass('disabled')) {
addToCurrent(true);
}
return false; return false;
}); });
$('a#action_PlayAlbum').click(function () { $('a#action_PlayAlbum').click(function () {
$('#CurrentPlaylistContainer tbody').empty(); if (!$(this).hasClass('disabled')) {
addToCurrent(true); $('#CurrentPlaylistContainer tbody').empty();
// Start playing song addToCurrent(true);
var first = $('#CurrentPlaylistContainer tr.song').first(); // Start playing song
changeTrack(first); var first = $('#CurrentPlaylistContainer tr.song').first();
changeTrack(first);
}
return false; return false;
}); });
$('#action_RefreshArtists').click(function () { $('#action_RefreshArtists').click(function () {
@ -391,15 +427,19 @@
return false; return false;
}); });
$('#action_SelectAll').click(function () { $('#action_SelectAll').click(function () {
$('#Albums tr.song').each(function () { if (!$(this).hasClass('disabled')) {
$(this).addClass('selected'); $('#Albums tr.song').each(function () {
}); $(this).addClass('selected');
});
}
return false; return false;
}); });
$('#action_SelectNone').click(function () { $('#action_SelectNone').click(function () {
$('#Albums tr.song').each(function () { if (!$(this).hasClass('disabled')) {
$(this).removeClass('selected'); $('#Albums tr.song').each(function () {
}); $(this).removeClass('selected');
});
}
return false; return false;
}); });
$('input#Search').keydown(function (e) { $('input#Search').keydown(function (e) {
@ -410,16 +450,55 @@
}); });
$('#action_Search').click(function () { $('#action_Search').click(function () {
var query = $('#Search').val(); var query = $('#Search').val();
var type = $('#SearchType').val(); if (query != '') {
search(type, query); var type = $('#SearchType').val();
$('#Search').val(""); search(type, query);
$('#Search').val("");
}
return false; return false;
}); });
$('#action_PreviousAlbumList').live('click', function () {
var type = $('#status_Library').data('type');
var offset = 0;
if ($('#status_Library').data('offset') != '') {
offset = $('#status_Library').data('offset');
}
var currOffset = 15;
if (getCookie('AutoAlbumSize')) {
currOffset = getCookie('AutoAlbumSize');
}
if (offset > 0) {
$('#status_Library').data('offset', parseInt(offset) - parseInt(currOffset));
getAlbumListBy(type, parseInt(offset) - parseInt(currOffset));
}
return false;
});
$('#action_NextAlbumList').live('click', function () {
var currOffset = 15;
if (getCookie('AutoAlbumSize')) {
currOffset = getCookie('AutoAlbumSize');
}
var count = $('#AlbumContainer tr.album').size();
if (count == currOffset) {
var type = $('#status_Library').data('type');
var offset = 0;
if ($('#status_Library').data('offset') != '') {
offset = $('#status_Library').data('offset');
}
$('#status_Library').data('offset', parseInt(offset) + parseInt(currOffset));
getAlbumListBy(type, parseInt(offset) + parseInt(currOffset));
}
return false;
});
// Current Playlist Click Events // Current Playlist Click Events
$('#action_Shuffle').live('click', function () { $('#action_Shuffle').live('click', function () {
//$('#CurrentPlaylistContainer tbody tr.song').shuffle();
$('#CurrentPlaylistContainer tbody tr.song:not(#CurrentPlaylistContainer tbody tr.playing)').shuffle(); $('#CurrentPlaylistContainer tbody tr.song:not(#CurrentPlaylistContainer tbody tr.playing)').shuffle();
refreshRowColor('#CurrentPlaylistContainer tbody'); /* Sets currently playing song first in list after sort
$('#CurrentPlaylistContainer tbody tr.song').shuffle();
$('#CurrentPlaylistContainer tbody tr.playing').insertBefore($('#CurrentPlaylistContainer tbody tr:first'));
*/
$('#CurrentPlaylistContainer thead').find('th').removeClass('sorted ascending descending');
var songid = $('#CurrentPlaylistContainer tbody tr.playing').attr('childid'); var songid = $('#CurrentPlaylistContainer tbody tr.playing').attr('childid');
if (songid !== undefined) { if (songid !== undefined) {
$('#CurrentPlaylist').scrollTo($('#' + songid), 400); $('#CurrentPlaylist').scrollTo($('#' + songid), 400);
@ -431,18 +510,20 @@
deleteCurrentPlaylist(); deleteCurrentPlaylist();
return false; return false;
}); });
$('a#action_AddCurrentToPlaylist').click(function () { $('#action_AddCurrentToPlaylist').click(function () {
var submenu = $('div#submenu_AddCurrentToPlaylist'); if (!$(this).hasClass('disabled')) {
if (submenu.is(":visible")) { var submenu = $('div#submenu_AddCurrentToPlaylist');
submenu.fadeOut(); if (submenu.is(":visible")) {
} else { submenu.fadeOut();
loadPlaylistsForMenu('submenu_AddCurrentToPlaylist'); } else {
//get the position of the placeholder element loadPlaylistsForMenu('submenu_AddCurrentToPlaylist');
pos = $(this).offset(); //get the position of the placeholder element
width = $(this).width(); pos = $(this).offset();
height = $(this).height(); width = $(this).width();
//show the menu directly over the placeholder height = $(this).height();
submenu.css({ "left": (pos.left) + "px", "top": (pos.top + height + 14) + "px" }).fadeIn(400); //show the menu directly over the placeholder
submenu.css({ "left": (pos.left) + "px", "top": (pos.top + height + 14) + "px" }).fadeIn(400);
}
} }
}); });
$("#submenu_AddCurrentToPlaylist a").live("click", function (event) { $("#submenu_AddCurrentToPlaylist a").live("click", function (event) {
@ -506,31 +587,34 @@
}); });
$('#songdetails').mouseout(function () { $('#songdetails').mouseout(function () {
$(this).removeClass('hover') $(this).removeClass('hover')
//$('div.submenu').hide();
}); });
$('#CurrentPlaylist').mouseenter(function () { $('.tabcontent').mouseenter(function () {
var html = $('#status').html(); $('.status').each(function (i) {
if (html != '') { if ($(this).hasClass('on')) {
$('#status').fadeIn(); $(this).fadeIn();
} }
});
$('#CurrentPlaylist').mouseleave(function () {
$('#status').stop().fadeOut();
});
$('#action_CurrentSelectAll').click(function () {
var count = 0;
$('#CurrentPlaylist tr.song').each(function () {
$(this).addClass('selected');
count++;
}); });
updateMessage(count + ' Song(s) Selected'); });
$('.tabcontent').mouseleave(function () {
$('.status').stop().fadeOut();
});
$('#action_CurrentSelectAll').click(function () {
if (!$(this).hasClass('disabled')) {
var count = 0;
$('#CurrentPlaylist tr.song').each(function () {
$(this).addClass('selected');
count++;
});
updateMessage(count + ' Song(s) Selected');
}
return false; return false;
}); });
$('#action_CurrentSelectNone').click(function () { $('#action_CurrentSelectNone').click(function () {
$('#CurrentPlaylist tr.song').each(function () { if (!$(this).hasClass('disabled')) {
$(this).removeClass('selected'); $('#CurrentPlaylist tr.song').each(function () {
}); $(this).removeClass('selected');
});
}
return false; return false;
}); });
$('#action_AutoPilot').click(function () { $('#action_AutoPilot').click(function () {
@ -546,6 +630,7 @@
if ($('#CurrentPlaylistContainer tbody').html() == '') { if ($('#CurrentPlaylistContainer tbody').html() == '') {
$('#CurrentPlaylistContainer tbody').empty(); $('#CurrentPlaylistContainer tbody').empty();
getRandomSongList('', '#CurrentPlaylistContainer tbody', '', ''); getRandomSongList('', '#CurrentPlaylistContainer tbody', '', '');
$('#currentActions a.button').removeClass('disabled');
} }
} }
$(this).attr("title", msg); $(this).attr("title", msg);
@ -623,8 +708,8 @@
return false; return false;
}); });
$('#action_ShufflePlaylist').live('click', function () { $('#action_ShufflePlaylist').live('click', function () {
$('#TrackContainer thead').find('th').removeClass('sorted ascending descending');
$('#TrackContainer tbody tr.song').shuffle(); $('#TrackContainer tbody tr.song').shuffle();
refreshRowColor('#TrackContainer tbody');
return false; return false;
}); });
@ -857,25 +942,20 @@
return false; return false;
}); });
/*
// JQuery UI Sortable - Drag and drop sorting // JQuery UI Sortable - Drag and drop sorting
var fixHelper = function (e, ui) { var fixHelper = function (e, ui) {
ui.children().each(function () { ui.children().each(function () {
$(this).width($(this).width()); $(this).width($(this).width());
}); });
return ui; return ui;
}; };
$("#CurrentPlaylistContainer tbody").sortable({ $("#CurrentPlaylistContainer tbody").sortable({
helper: fixHelper, helper: fixHelper
stop: function () {
refreshRowColor('#CurrentPlaylistContainer tbody');
}
}).disableSelection(); }).disableSelection();
$("#TrackContainer tbody").sortable({ $("#TrackContainer tbody").sortable({
helper: fixHelper, helper: fixHelper
stop: function () {
refreshRowColor('#TrackContainer tbody');
}
}).disableSelection(); }).disableSelection();
*/
}); // End document.ready }); // End document.ready

View file

@ -2,7 +2,7 @@
"manifest_version": 2, "manifest_version": 2,
"name": "MiniSub (Beta)", "name": "MiniSub (Beta)",
"description": "MiniSub - HTML5 Mini Player for Subsonic", "description": "MiniSub - HTML5 Mini Player for Subsonic",
"version": "2.1.7", "version": "2.2.0",
"app": { "app": {
"launch": { "launch": {
"local_path": "index.html" "local_path": "index.html"

View file

@ -15,9 +15,6 @@ h3.title {
color: #f2f2f2; color: #f2f2f2;
} }
.odd { background: none; }
.even { background: #272727; }
#content #content
{ {
background: #222222; background: #222222;
@ -98,14 +95,18 @@ h3.title {
{ {
color: #d6d469; color: #d6d469;
background: #2e2e2e; background: #2e2e2e;
border: 1px solid #5a5a5a; border: 1px solid #1d1d1d;
} }
#status .status
{ {
background: #222; background: #222;
border-top: 1px solid #1D1D1D; border-top: 1px solid #1D1D1D;
border-left: 1px solid #1D1D1D; border-left: 1px solid #1D1D1D;
} }
.status a
{
color: #d6d469;
}
#player #player
{ {
background: #2E2E2E; background: #2E2E2E;
@ -146,7 +147,7 @@ a.button:hover {
-moz-box-shadow: 0 2px 0 rgba(242, 242, 242, 0.2) -moz-box-shadow: 0 2px 0 rgba(242, 242, 242, 0.2)
-webkit-box-shadow:0 2px 5px rgba(242, 242, 242, 0.2); -webkit-box-shadow:0 2px 5px rgba(242, 242, 242, 0.2);
box-shadow: 0 1px 2px rgba(242, 242, 242, 0.15); box-shadow: 0 1px 2px rgba(242, 242, 242, 0.15);
border: solid 1px #5a5a5a; border-color: #5a5a5a;
} }
a.button:active { a.button:active {
color: #000; color: #000;
@ -155,8 +156,22 @@ a.button:active {
a.selected { a.selected {
color: #939393; color: #939393;
border-color: #5a5a5a; border-color: #5a5a5a;
-moz-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2) -webkit-box-shadow:0 2px 5px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 2px 0 rgba(242, 242, 242, 0.2)
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); -webkit-box-shadow:0 2px 5px rgba(242, 242, 242, 0.2);
box-shadow: 0 1px 2px rgba(242, 242, 242, 0.15);
background: #161616;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#161616),to(#111111));
background: -moz-linear-gradient(linear,0% 40%,0% 70%,from(#161616),to(#111111));
}
a.disabled {
color: #3D3D3D;
background: #2E2E2E;
}
a.disabled:hover {
color: #3D3D3D;
border-color: #1d1d1d;
-moz-box-shadow: none;
box-shadow: none;
} }
ul.simplelist li ul.simplelist li
{ {
@ -196,8 +211,13 @@ ul.simplelist li.selected
} }
table.songlist th { table.songlist th {
color: #F2F2F2; color: #F2F2F2;
border-bottom: 1px solid #2e2e2e;
background: #2E2E2E;
} }
table.songlist tr:hover table.songlist th:hover, table.songlist th.sorted {
background: #272727;
}
table.songlist tr.album:hover
{ {
background: #1d1d1d; background: #1d1d1d;
} }
@ -212,6 +232,10 @@ table.songlist tr.album td.albumart img
table.songlist tr.song { table.songlist tr.song {
border-bottom: 1px solid #232323; border-bottom: 1px solid #232323;
} }
table.songlist tr.song:hover
{
background: #1d1d1d;
}
table.songlist tr.song td.album img table.songlist tr.song td.album img
{ {
border: 1px solid #232323; border: 1px solid #232323;
@ -225,13 +249,16 @@ table.songlist tr.song td.album a:hover
color: #d6d469; color: #d6d469;
text-decoration: underline; text-decoration: underline;
} }
table.songlist tr.selected table.songlist tr:nth-child(odd) { background-color: #272727; }
{ table.songlist tr:nth-child(even) { background-color: #2e2e2e; }
background: #3a3a3a;
}
table.songlist tr.playing { table.songlist tr.playing {
background: #161616; background: #161616;
} }
table.songlist tr.selected
{
background: #3a3a3a;
border-bottom: 1px solid #232323;
}
#submenu_CurrentPlaylist #submenu_CurrentPlaylist
{ {
background: #2E2E2E; background: #2E2E2E;
@ -254,4 +281,10 @@ fieldset
#donate { #donate {
background: #232323; background: #232323;
border: 1px solid #1D1D1D; border: 1px solid #1D1D1D;
}
::-webkit-scrollbar-thumb {
background: rgba(34, 34, 34, 0.8);
}
::-webkit-scrollbar-thumb:window-inactive {
background: rgba(34, 34, 34, 0.2);
} }

View file

@ -31,8 +31,10 @@ h3.title
.alignright { text-align: right; } .alignright { text-align: right; }
.aligncenter { text-align: center; } .aligncenter { text-align: center; }
.padright { padding: 0 10px 0 0; } .padright { padding: 0 10px 0 0; }
/* Old: Using CSS3
.odd { background: #fff; } .odd { background: #fff; }
.even { background: #f4f4f4; } .even { background: #f4f4f4; }
*/
.red { color: #E64F4C; } .red { color: #E64F4C; }
.italic { font-style: italic; } .italic { font-style: italic; }
.beer { font-size: 17px; } .beer { font-size: 17px; }
@ -161,7 +163,7 @@ a#logo:hover
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
background: #fff; background: #fff;
border-right: 1px solid #cbcbcb; border-right: 1px solid #f2f2f2;
position: absolute; position: absolute;
top: 39px; top: 39px;
left: 60px; left: 60px;
@ -225,7 +227,7 @@ a#logo:hover
position: absolute; position: absolute;
z-index: 99; z-index: 99;
top: 0; top: 0;
left: 790px; right: 10px;
} }
#messages .message #messages .message
{ {
@ -236,11 +238,13 @@ a#logo:hover
margin: 2px 0 2px 0; margin: 2px 0 2px 0;
background: #fff; background: #fff;
border: 1px solid #A6CBF3; border: 1px solid #A6CBF3;
border-radius: 4px 4px 4px 4px;
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
opacity: 0.8;
} }
#status .status
{ {
display: none; display: none;
width: 180px;
overflow: hidden; overflow: hidden;
font-size: 12px; font-size: 12px;
text-align: center; text-align: center;
@ -249,10 +253,32 @@ a#logo:hover
bottom: 86px; bottom: 86px;
right: 4px; right: 4px;
background: #f2f2f2; background: #f2f2f2;
padding: 2px 5px; padding: 2px 10px;
border-top: 1px solid #CBCBCB; border-top: 1px solid #CBCBCB;
border-left: 1px solid #CBCBCB; border-left: 1px solid #CBCBCB;
opacity: .7; opacity: .9;
}
.status a
{
color: #545454;
text-decoration: none;
font-size: 12px;
}
.status a:hover
{
text-decoration: underline;
}
.status a.previous
{
margin: 0 5px 0 0;
}
.status a.next
{
margin: 0 0 0 5px;
}
.on
{
display: block;
} }
/* Library Style */ /* Library Style */
ul.simplelist ul.simplelist
@ -337,13 +363,9 @@ ul.mainlist li.item a.add:hover
{ {
background: url('../images/plus_8x8.png') no-repeat 6px center #DEECFB; background: url('../images/plus_8x8.png') no-repeat 6px center #DEECFB;
} }
#AlbumContainer #AlbumContainer, #TrackContainer, #PodcastContainer
{ {
margin: 5px 5px 5px 206px; margin: 5px 5px 5px 221px;
}
#TrackContainer, #PodcastContainer
{
margin: 5px 5px 5px 206px;
} }
#CurrentPlaylistContainer tr.song a.add #CurrentPlaylistContainer tr.song a.add
{ {
@ -381,9 +403,25 @@ table.songlist th
{ {
font-size: 14px; font-size: 14px;
font-variant: small-caps; font-variant: small-caps;
padding: 5px 4px; padding: 5px 5px 5px 12px;
cursor: pointer;
border-bottom: 1px solid #ffffff;
background: #fff;
} }
table.songlist tr:hover table.songlist th:hover
{
background: #fafafa;
}
table.songlist th.sorted {
background: #F2F3F4;
}
table.songlist th.sorted.ascending:after {
content: " \2191";
}
table.songlist th.sorted.descending:after {
content: " \2193";
}
table.songlist tr.album:hover
{ {
background: #EEF5FD; background: #EEF5FD;
} }
@ -480,6 +518,7 @@ table.songlist tr.album a.favorite
display: block; display: block;
background: url('../images/star_yo_12x12.png') 2px center no-repeat; background: url('../images/star_yo_12x12.png') 2px center no-repeat;
} }
table.songlist tr.song table.songlist tr.song
{ {
cursor: pointer; cursor: pointer;
@ -499,13 +538,9 @@ table.songlist tr.song td.itemactions
height: 18px; height: 18px;
} }
table.songlist tr.song td.track table.songlist tr.song td.track
{
width: 40px;
text-align: right;
}
table.songlist tr.song td.published
{ {
width: 80px; width: 80px;
text-align: right;
} }
table.songlist tr.song td.title table.songlist tr.song td.title
{ {
@ -604,6 +639,8 @@ table.songlist tr.song a.favorite
display: block; display: block;
background: url('../images/star_yo_12x12.png') center 3px no-repeat; background: url('../images/star_yo_12x12.png') center 3px no-repeat;
} }
table.songlist tr:nth-child(odd) { background-color:#f4f4f4; }
table.songlist tr:nth-child(even) { background-color:#fff; }
table.songlist tr.playing table.songlist tr.playing
{ {
background-color: #DEEBFA; background-color: #DEEBFA;
@ -622,50 +659,6 @@ table.songlist tr.selected td:first-child
{ {
background: url('../images/check_8x7.png') 10px 16px no-repeat; background: url('../images/check_8x7.png') 10px 16px no-repeat;
} }
table.songlist tr.selected td.album a
{
color: #f2f2f2;
}
/* tablesorter style */
table.tablesorter {
font-family:arial;
background-color: #CDCDCD;
margin:10px 0pt 15px;
font-size: 8pt;
width: 100%;
text-align: left;
}
table.tablesorter thead tr th, table.tablesorter tfoot tr th {
background-color: #e6EEEE;
border: 1px solid #FFF;
font-size: 8pt;
padding: 4px;
}
table.tablesorter thead tr .header {
background-image: url(../images/bg.gif);
background-repeat: no-repeat;
background-position: center right;
cursor: pointer;
}
table.tablesorter tbody td {
color: #3D3D3D;
padding: 4px;
background-color: #FFF;
vertical-align: top;
}
table.tablesorter tbody tr.odd td {
background-color:#F0F0F6;
}
table.tablesorter thead tr .headerSortUp {
background-image: url(../images/asc.gif);
}
table.tablesorter thead tr .headerSortDown {
background-image: url(../images/desc.gif);
}
table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
background-color: #8dbdd8;
}
#ArtistContainer #ArtistContainer
{ {
min-height: 360px; min-height: 360px;
@ -714,7 +707,7 @@ background-color: #8dbdd8;
margin: 4px 0 0 0; margin: 4px 0 0 0;
padding: 0 0 0 5px; padding: 0 0 0 5px;
} }
#songactions #songActions
{ {
float: left; float: left;
} }
@ -1122,14 +1115,45 @@ a.selected {
border-color: #999; border-color: #999;
-moz-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2) -webkit-box-shadow:0 2px 5px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2) -webkit-box-shadow:0 2px 5px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
background: #fdfdfd;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#ffffff),to(#fdfdfd));
background: -moz-linear-gradient(linear,0% 40%,0% 70%,from(#ffffff),to(#fdfdfd));
}
a.disabled {
color: #B7B7B7;
background: #f1f1f1;
}
a.disabled:hover {
color: #B7B7B7;
border-color: #dcdcdc;
-moz-box-shadow: none;
box-shadow: none;
} }
a.button img.pad { margin: 1px 0 -1px 0; } a.button img.pad { margin: 1px 0 -1px 0; }
.shadow .shadow
{ {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.2); box-shadow: 0 0 4px rgba(0, 0, 0, 0.2);
} }
/* Scrollbar Style */
::-webkit-scrollbar {
width: 14px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.2);
-webkit-border-radius: 12px;
border-radius: 12px;
}
::-webkit-scrollbar-thumb {
-webkit-border-radius: 12px;
border-radius: 12px;
background: rgba(237, 237, 237, 0.4);
-webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.2);
}
::-webkit-scrollbar-thumb:window-inactive {
background: rgba(237, 237, 237, 0.2);
}
/* Form Style */ /* Form Style */
input input
{ {