Add 'Refresh' button to update libraries (#222)

Add 'Refresh' button to update libraries.

Tweak folder icons and context menus.

Fixes #136.
This commit is contained in:
John Cass 2017-01-22 07:16:52 +02:00 committed by GitHub
parent 8345fbb9c0
commit 9856685a00
7 changed files with 101 additions and 51 deletions

View File

@ -111,6 +111,7 @@ v2.4.0 (UNRELEASED)
- Add 'Show Track Info' popup which can be activated from any context menu. The popup includes the URI of the track,
which can be inserted into various lists elsewhere in the player.
- Updated icon set for font-awesome 4.7.0.
- Added 'Refresh' button for refreshing libraries. (Addresses: `#75 <https://github.com/pimusicbox/mopidy-musicbox-webclient/issues/75>`_).
**Fixes**
@ -121,6 +122,7 @@ v2.4.0 (UNRELEASED)
- Use correct icons for folders, audio, and other files when browsing local files.
- Now initializes the GUI properly, even if the user is offline or the Mopidy server cannot be reached.
- Fixed `Alarm Clock <https://pypi.python.org/pypi/Mopidy-AlarmClock/>`_ detection.
- When browsing the library using the local 'File' extension, only playable audio files will have context menu icons.
v2.3.0 (2016-05-15)
-------------------

View File

@ -118,7 +118,6 @@
/******************
* Track Slider *
******************/
#trackslider {
display: inline;
width: 100%;
@ -366,6 +365,10 @@ span.hostInfo {
background-color: #ccc !important;
}
.refreshLibraryBtnDiv {
display: none;
}
/**********************
* Now Playing area *

View File

@ -404,7 +404,16 @@
<!--/playlistspane-->
<div data-role="content" id="browsepane" class="pane">
<h4>Browse</h4>
<div class="ui-grid-a">
<div class="ui-block-a">
<h4>Browse</h4>
</div>
<div align="right" class="ui-block-b refreshLibraryBtnDiv" data-role="controlgroup" data-type="horizontal">
<button id="refreshLibraryBtn" class="btn" type="button" title="Refresh library">
<i class="fa fa-refresh"></i>
</button>
</div>
</div>
<div class="ui-grid">
<ul id="browsetable" class="table"></ul>
</div>

View File

@ -416,6 +416,14 @@
return false
},
refreshLibrary: function () {
var uri = $('#refreshLibraryBtn').data('url')
mopidy.library.refresh({'uri': uri}).then(function () {
library.getBrowseDir(uri)
})
return false
},
/** ***********
* Buttons *
*************/

View File

@ -75,8 +75,8 @@ var radioExtensionsList = ['somafm', 'tunein', 'dirble', 'audioaddict']
var uriClassList = [
['spotify', 'fa-spotify'],
['spotifytunigo', 'fa-spotify'],
['local', 'fa-file-sound-o'],
['file', 'fa-file-o'],
['local', 'fa-folder-o'],
['file', 'fa-folder-o'],
['m3u', 'fa-file-sound-o'],
['podcast', 'fa-rss-square'],
['podcast+file', 'fa-rss-square'],
@ -240,13 +240,9 @@ function renderSongLi (previousTrack, track, nextTrack, uri, tlid, target, curre
var onClick = ''
var html = ''
track.name = validateTrackName(track, currentIndex)
// Leave out unplayable items
if (track.name.substring(0, 12) === '[unplayable]') {
return html
}
// Streams
if (track.length === -1) {
html += '<li class="albumli"><a href="#"><h1><i class="' + getMediaClass(track.uri) + '"></i> ' + track.name + ' [Stream]</h1></a></li>'
html += '<li class="albumli"><a href="#"><h1><i class="' + getMediaClass(track) + '"></i> ' + track.name + ' [Stream]</h1></a></li>'
return html
}
@ -257,11 +253,13 @@ function renderSongLi (previousTrack, track, nextTrack, uri, tlid, target, curre
onClick = 'return controls.playTracks(\'\', mopidy, \'' + track.uri + '\', \'' + uri + '\');'
}
html +=
'<li class="song albumli" id="' + getjQueryID(target, track.uri) + '" tlid="' + tlid + '">' +
'<a href="#" class="moreBtn" onclick="return popupTracks(event, \'' + uri + '\',\'' + track.uri + tlidParameter + '\');">' +
'<i class="fa fa-play-circle-o"></i></a>' +
'<a href="#" onclick="' + onClick + '"><h1><i class="' + getMediaClass(track.uri) + '"></i> ' + track.name + '</h1>'
html += '<li class="song albumli" id="' + getjQueryID(target, track.uri) + '" tlid="' + tlid + '">'
if (isPlayable(track)) {
// Show popup icon for audio files or 'tracks' of other scheme types
html += '<a href="#" class="moreBtn" onclick="return popupTracks(event, \'' + uri + '\',\'' + track.uri + tlidParameter + '\');">' +
'<i class="fa fa-play-circle-o"></i></a>'
}
html += '<a href="#" onclick="' + onClick + '"><h1><i class="' + getMediaClass(track) + '"></i> ' + track.name + '</h1>'
if (listLength === 1 || (!hasSameAlbum(previousTrack, track) && !hasSameAlbum(track, nextTrack))) {
html += renderSongLiAlbumInfo(track)
@ -309,7 +307,7 @@ function renderSongLiDivider (previousTrack, track, nextTrack, target) {
html +=
'<li class="albumdivider"><a href="#" onclick="return library.showAlbum(\'' + track.album.uri + '\');">' +
'<img id="' + getjQueryID(target + '-cover', track.uri) + '" class="artistcover" width="30" height="30"/>' +
'<h1><i class="' + getMediaClass(track.uri) + '"></i> ' + track.album.name + '</h1><p>' +
'<h1>' + track.album.name + '</h1><p>' +
renderSongLiTrackArtists(track) + '</p></a></li>'
// Retrieve album covers
images.setAlbumImage(track.uri, getjQueryID(target + '-cover', track.uri, true), mopidy, 'small')
@ -317,7 +315,7 @@ function renderSongLiDivider (previousTrack, track, nextTrack, target) {
// Small divider
html += '<li class="smalldivider"> &nbsp;</li>'
}
if (typeof target !== 'undefined' && target.length > 0) {
if (html.length > 0 && typeof target !== 'undefined' && target.length > 0) {
target = getjQueryID(target, track.uri, true)
$(target).before(html)
}
@ -494,26 +492,52 @@ function getScheme (uri) {
return uri.split(':')[0].toLowerCase()
}
function isAudioFile (uri) {
var ext = uri.split('.').pop().toLowerCase()
return $.inArray(ext, audioExt) !== -1
function isPlayable (track) {
if (typeof track.type === 'undefined' || track.type === 'track') {
if (getScheme(track.uri) === 'file') {
var ext = track.uri.split('.').pop().toLowerCase()
if ($.inArray(ext, audioExt) === -1) {
// Files must have the correct extension
return false
}
}
return true
}
return false
}
function isStreamUri (uri) {
var a = validUri(uri)
var b = radioExtensionsList.indexOf(getScheme(uri)) >= 0
return a || b
return validUri(uri) || radioExtensionsList.indexOf(getScheme(uri)) >= 0
}
function getMediaClass (uri) {
var scheme = getScheme(uri)
if (scheme === 'file' && isAudioFile(uri)) {
return 'fa fa-file-sound-o'
}
for (var i = 0; i < uriClassList.length; i++) {
if (scheme === uriClassList[i][0]) {
return 'fa ' + uriClassList[i][1]
function getMediaClass (track) {
var type = track.type
if (typeof type === 'undefined' || type === 'track') {
if (isPlayable(track)) {
if (isStreamUri(track.uri)) {
return 'fa fa-rss' // Stream
} else {
return 'fa fa-file-sound-o' // Sound file (default)
}
} else {
return 'fa fa-file-o' // Unplayable file
}
} else if (type === 'directory') {
for (var i = 0; i < uriClassList.length; i++) {
if (getScheme(track.uri) === uriClassList[i][0]) {
return 'fa ' + uriClassList[i][1] // Mapped service directory
}
}
return 'fa fa-folder-o' // Unmapped directory
} else if (type === 'album') {
// return 'fa fa-bullseye' // Album
return 'fa fa-folder-o'
} else if (type === 'artist') {
// return 'fa fa-user-circle-o' // Artist
return 'fa fa-folder-o'
} else if (type === 'playlist') {
// return 'fa fa-star' // Playlist
return ''
}
return ''
}

View File

@ -145,7 +145,7 @@
tokens = {
'id': results.artists[i].uri,
'name': results.artists[i].name,
'class': getMediaClass(results.artists[i].uri)
'class': getMediaClass(results.artists[i])
}
// Add 'Show all' item after a certain number of hits.
@ -173,7 +173,7 @@
'albumName': results.albums[i].name,
'artistName': '',
'albumYear': results.albums[i].date,
'class': getMediaClass(results.albums[i].uri)
'class': getMediaClass(results.albums[i])
}
if (results.albums[i].artists) {
for (j = 0; j < results.albums[i].artists.length; j++) {
@ -215,14 +215,23 @@
showLoading(true)
if (!rootdir) {
browseStack.pop()
rootdir = browseStack[browseStack.length - 1]
rootdir = browseStack[browseStack.length - 1] || null
} else {
browseStack.push(rootdir)
if (rootdir !== browseStack[browseStack.length - 1]) {
browseStack.push(rootdir)
}
}
if (!rootdir) {
rootdir = null
}
mopidy.library.browse({'uri': rootdir}).then(processBrowseDir, console.error)
mopidy.library.browse({'uri': rootdir}).then(function (resultArr) {
processBrowseDir(resultArr)
if (rootdir === null) {
$('.refreshLibraryBtnDiv').hide()
} else {
$('.refreshLibraryBtnDiv').show()
$('#refreshLibraryBtn').data('url', rootdir)
$('#refreshLibraryBtn').off('click')
$('#refreshLibraryBtn').one('click', controls.refreshLibrary)
}
}, console.error)
},
getCurrentPlaylist: function () {

View File

@ -90,8 +90,9 @@ function processBrowseDir (resultArr) {
var length = 0 || resultArr.length
customTracklists[BROWSE_TABLE] = []
var html = ''
var i
for (var i = 0, index = 0; i < resultArr.length; i++) {
for (i = 0, index = 0; i < resultArr.length; i++) {
if (resultArr[i].type === 'track') {
previousRef = ref || undefined
nextRef = i < resultArr.length - 1 ? resultArr[i + 1] : undefined
@ -105,14 +106,8 @@ function processBrowseDir (resultArr) {
index++
} else {
var iconClass = ''
if (browseStack.length > 0 && resultArr[i].type === 'directory') {
iconClass = 'fa fa-folder-o'
} else {
iconClass = getMediaClass(resultArr[i].uri)
}
html += '<li><a href="#" onclick="return library.getBrowseDir(this.id);" id="' + resultArr[i].uri + '">' +
'<h1><i class="' + iconClass + '"></i> ' + resultArr[i].name + '</h1></a></li>'
'<h1><i class="' + getMediaClass(resultArr[i]) + '"></i> ' + resultArr[i].name + '</h1></a></li>'
}
}
@ -124,22 +119,22 @@ function processBrowseDir (resultArr) {
mopidy.library.lookup({'uris': uris}).then(function (resultDict) {
// Break into albums and put in tables
var track, previousTrack, nextTrack, uri
$.each(resultArr, function (i, ref) {
if (ref.type === 'track') {
for (i = 0, index = 0; i < resultArr.length; i++) {
if (resultArr[i].type === 'track') {
previousTrack = track || undefined
if (i < resultArr.length - 1 && resultDict[resultArr[i + 1].uri]) {
nextTrack = resultDict[resultArr[i + 1].uri][0]
} else {
nextTrack = undefined
}
track = resultDict[ref.uri][0]
track = resultDict[resultArr[i].uri][0]
popupData[track.uri] = track // Need full track info in popups in order to display albums and artists.
if (uris.length === 1 || (previousTrack && !hasSameAlbum(previousTrack, track) && !hasSameAlbum(track, nextTrack))) {
renderSongLiAlbumInfo(track, BROWSE_TABLE)
}
renderSongLiDivider(previousTrack, track, nextTrack, BROWSE_TABLE)
}
})
}
showLoading(false)
}, console.error)
} else {
@ -166,7 +161,7 @@ function processGetPlaylists (resultArr) {
} else if (isFavouritesPlaylist(resultArr[i])) {
favourites = li_html + '&hearts; Musicbox Favourites</a></li>'
} else {
tmp = tmp + li_html + '<i class="' + getMediaClass(resultArr[i].uri) + '"></i> ' + resultArr[i].name + '</a></li>'
tmp = tmp + li_html + '<i class="' + getMediaClass(resultArr[i]) + '"></i> ' + resultArr[i].name + '</a></li>'
}
}
// Prepend the user's Spotify "Starred" playlist and favourites to the results. (like Spotify official client).