User's favourite streams now saved as an m3u playlist.
This commit is contained in:
parent
d211b92447
commit
0090699818
@ -411,33 +411,22 @@
|
|||||||
<form>
|
<form>
|
||||||
<div class="ui-grid-a pl-breakpoint">
|
<div class="ui-grid-a pl-breakpoint">
|
||||||
<div class="ui-block-a" style="padding: 5px">
|
<div class="ui-block-a" style="padding: 5px">
|
||||||
<p>Select a service and add the URL of the stream you want to listen to.
|
<p>Play a specific stream/track and optionally save it to your favourites.
|
||||||
<select id="selectstreamservice" data-native-menu="true">
|
<button class="btn" type="button" onclick="return getCurrentlyPlaying();">
|
||||||
<option value="">Internet Radio (mp3, m3u, asx, etc)</option>
|
Get currently playing
|
||||||
<option value="yt">YouTube</option>
|
</button>
|
||||||
<option value="">Spotify Uri</option>
|
<input id="streamuriinput" placeholder="URI" class="span2" data-clear-btn="true"
|
||||||
<option value="sc">SoundCloud</option>
|
onkeypress="return streamPressed(event.keyCode);" id="appendedInputButton" type="text"/>
|
||||||
<option value="podcast">Podcast</option>
|
<button class="btn" type="button" onclick="return playStreamUri();">
|
||||||
</select>
|
Play
|
||||||
|
</button>
|
||||||
|
|
||||||
<input id="streamuriinput" placeholder="URI" class="span2" data-clear-btn="true"
|
<input id="streamnameinput" placeholder="Name" class="span2" data-clear-btn="true"
|
||||||
onkeypress="return streamPressed(event.keyCode);" id="appendedInputButton" type="text"/>
|
onkeypress="return streamPressed(event.keyCode);" id="appendedInputButton" type="text"/>
|
||||||
<button class="btn" type="button" onclick="return playStreamUri();">
|
<button class="btn" type="button" onclick="return addFavourite();">
|
||||||
Play
|
Save
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<p>Put in a name and hit the Save button to save the stream in your browser (not on the server yet). <!-- To find stations, use the Browse function with extensions like Dirble or TuneIn, the right values will appear in these boxes automatically. Or use websites like <a href="http://www.listenlive.eu/" target="_blank">Listenlive</a> or <a
|
|
||||||
href="http://www.dirble.com/" target="_blank">Dirble</a>.</p> -->
|
|
||||||
|
|
||||||
<input id="streamnameinput" placeholder="Name" class="span2" data-clear-btn="true"
|
|
||||||
onkeypress="return streamPressed(event.keyCode);" id="appendedInputButton" type="text"/>
|
|
||||||
<button class="btn" type="button" onclick="return saveStreamUri();">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<br/>
|
<br/>
|
||||||
<button class="btn" type="button" onclick="$('#streamuriinput').val(songdata.track.uri); return true;">
|
|
||||||
Add currently playing url
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui-block-b" style="padding: 5px">
|
<div class="ui-block-b" style="padding: 5px">
|
||||||
|
|||||||
153
mopidy_musicbox_webclient/static/js/controls.js
vendored
153
mopidy_musicbox_webclient/static/js/controls.js
vendored
@ -286,7 +286,7 @@ function doPlay() {
|
|||||||
if(isStreamUri(songdata.track.uri)) {
|
if(isStreamUri(songdata.track.uri)) {
|
||||||
mopidy.playback.stop();
|
mopidy.playback.stop();
|
||||||
} else {
|
} else {
|
||||||
mopidy.playback.pause();
|
mopidy.playback.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setPlayState(!play);
|
setPlayState(!play);
|
||||||
@ -497,8 +497,8 @@ function playStreamUri(uri) {
|
|||||||
mopidy.playback.stop();
|
mopidy.playback.stop();
|
||||||
//hide ios/android keyboard
|
//hide ios/android keyboard
|
||||||
document.activeElement.blur();
|
document.activeElement.blur();
|
||||||
$("input").blur();
|
|
||||||
clearQueue();
|
clearQueue();
|
||||||
|
$("input").blur();
|
||||||
mopidy.tracklist.add(null, null, nwuri);
|
mopidy.tracklist.add(null, null, nwuri);
|
||||||
mopidy.playback.play();
|
mopidy.playback.play();
|
||||||
} else {
|
} else {
|
||||||
@ -507,71 +507,108 @@ function playStreamUri(uri) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveStreamUri(nwuri) {
|
function getCurrentlyPlaying() {
|
||||||
var i = 0;
|
$('#streamuriinput').val(songdata.track.uri);
|
||||||
var name = $('#streamnameinput').val().trim();
|
var name = songdata.track.name;
|
||||||
var uri = nwuri || $('#streamuriinput').val().trim();
|
if (songdata.track.artists) {
|
||||||
var service = $('#selectstreamservice').val();
|
var artistStr = artistsToString(songdata.track.artists);
|
||||||
if (service) {
|
if (artistStr) {
|
||||||
uri = serviceupdateStreamUris + ':' + uri;
|
name = artistStr + ' - ' + name;
|
||||||
}
|
|
||||||
toast('Adding stream ' + uri, 500);
|
|
||||||
//add stream to list and check for doubles and add no more than 100
|
|
||||||
for (var key in streamUris) {
|
|
||||||
rs = streamUris[key];
|
|
||||||
if (i > 100) {
|
|
||||||
delete streamUris[key];
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
streamUris.unshift([name, uri]);
|
$('#streamnameinput').val(name);
|
||||||
$.cookie.json = true;
|
return true;
|
||||||
$.cookie('streamUris', streamUris);
|
|
||||||
updateStreamUris();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteStreamUri(uri) {
|
function getPlaylistByName(name, scheme, create) {
|
||||||
var i = 0;
|
return mopidy.playlists.filter({"name": name}).then(function(plists) {
|
||||||
for (var key in streamUris) {
|
for (var i = 0; i < plists.length; i++) {
|
||||||
rs = streamUris[key];
|
if (!scheme || getScheme(plists[i].uri) == scheme) {
|
||||||
if (rs && rs[1] == uri) {
|
return plists[i];
|
||||||
if (confirm("About to remove " + rs[0] + ". Sure?")) {
|
|
||||||
delete streamUris[key];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (create) {
|
||||||
$.cookie.json = true;
|
return mopidy.playlists.create(name, scheme).done(function(plist) {
|
||||||
$.cookie('streamUris', streamUris);
|
console.log("Created playlist '%s'", plist.name);
|
||||||
updateStreamUris();
|
return plist;
|
||||||
|
});
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStreamUris() {
|
|
||||||
var tmp = '';
|
|
||||||
$('#streamuristable').empty();
|
|
||||||
var child = '';
|
|
||||||
for (var key in streamUris) {
|
|
||||||
var rs = streamUris[key];
|
|
||||||
if (rs) {
|
|
||||||
name = rs[0] || rs[1];
|
|
||||||
child = '<li><span class="ui-icon ui-icon-delete ui-icon-shadow" style="float:right; margin: .5em; margin-top: .8em;"><a href="#" onclick="return deleteStreamUri(\'' + rs[1] + '\');"> </a></span>' +
|
|
||||||
'<i class="fa fa-rss" style="float: left; padding: .5em; padding-top: 1em;"></i>' +
|
|
||||||
' <a style="margin-left: 20px" href="#" onclick="return playStreamUri(\'' + rs[1] + '\');">';
|
|
||||||
child += '<h1>' + name + '</h1></a></li>';
|
|
||||||
tmp += child;
|
|
||||||
}
|
}
|
||||||
}
|
console.log("Can't find playist '%s", name);
|
||||||
$('#streamuristable').html(tmp);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initStreams() {
|
function getFavourites() {
|
||||||
$.cookie.json = true;
|
return getPlaylistByName(STREAMS_PLAYLIST_NAME,
|
||||||
tmpRS = $.cookie('streamUris');
|
STREAMS_PLAYLIST_SCHEME,
|
||||||
streamUris = tmpRS || streamUris;
|
true).then(function(playlist) {
|
||||||
updateStreamUris();
|
return playlist;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFavourite(uri, name) {
|
||||||
|
var uri = uri || $('#streamuriinput').val().trim();
|
||||||
|
var name = name || $('#streamnameinput').val().trim();
|
||||||
|
mopidy.library.lookup(null, [uri]).then(function(results) {
|
||||||
|
var newTracks = results[uri];
|
||||||
|
if (newTracks.length == 1) {
|
||||||
|
// TODO: Supporting adding an entire playlist?
|
||||||
|
if (name) {
|
||||||
|
newTracks[0].name = name; // User overrides name.
|
||||||
|
}
|
||||||
|
getFavourites().then(function(favourites) {
|
||||||
|
if (favourites) {
|
||||||
|
if (favourites.tracks) {
|
||||||
|
//Array.prototype.push.apply(favourites.tracks, newTracks)
|
||||||
|
favourites.tracks.push(newTracks[0]);
|
||||||
|
} else {
|
||||||
|
favourites.tracks = [newTracks[0]];
|
||||||
|
}
|
||||||
|
mopidy.playlists.save(favourites).then(function(s) {
|
||||||
|
showFavourites();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (newTracks.length == 0) {
|
||||||
|
console.log('No tracks to add');
|
||||||
|
} else {
|
||||||
|
console.log('Too many tracks (%d) to add', tracks.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteFavourite(index) {
|
||||||
|
getFavourites().then(function(favourites) {
|
||||||
|
if (favourites && favourites.tracks && index < favourites.tracks.length) {
|
||||||
|
var name = favourites.tracks[index].name;
|
||||||
|
if (confirm("Are you sure you want to remove '" + name + "'?")) {
|
||||||
|
favourites.tracks.splice(index, 1);
|
||||||
|
mopidy.playlists.save(favourites).then(function(s) {
|
||||||
|
showFavourites();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showFavourites() {
|
||||||
|
$('#streamuristable').empty();
|
||||||
|
getFavourites().then(function(favourites) {
|
||||||
|
if (favourites && favourites.tracks) {
|
||||||
|
tracks = favourites.tracks;
|
||||||
|
var tmp = '';
|
||||||
|
var child = '';
|
||||||
|
for (var i = 0; i < tracks.length; i++) {
|
||||||
|
child = '<li><span class="ui-icon ui-icon-delete ui-icon-shadow" style="float:right; margin: .5em; margin-top: .8em;"><a href="#" onclick="return deleteFavourite(\'' + i + '\');"> </a></span>' +
|
||||||
|
'<i class="fa fa-rss" style="float: left; padding: .5em; padding-top: 1em;"></i>' +
|
||||||
|
' <a style="margin-left: 20px" href="#" onclick="return playStreamUri(\'' + tracks[i].uri + '\');">';
|
||||||
|
child += '<h1>' + tracks[i].name + '</h1></a></li>';
|
||||||
|
tmp += child;
|
||||||
|
}
|
||||||
|
$('#streamuristable').html(tmp);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function haltSystem() {
|
function haltSystem() {
|
||||||
|
|||||||
@ -34,6 +34,9 @@ var newposition = 0;
|
|||||||
var playlisttracksScroll;
|
var playlisttracksScroll;
|
||||||
var playlistslistScroll;
|
var playlistslistScroll;
|
||||||
|
|
||||||
|
var STREAMS_PLAYLIST_NAME = '[Radio Streams]';
|
||||||
|
var STREAMS_PLAYLIST_SCHEME = 'm3u';
|
||||||
|
|
||||||
//array of cached playlists (not only user-playlists, also search, artist, album-playlists)
|
//array of cached playlists (not only user-playlists, also search, artist, album-playlists)
|
||||||
var playlists = {};
|
var playlists = {};
|
||||||
var currentplaylist;
|
var currentplaylist;
|
||||||
@ -152,6 +155,20 @@ function getAlbum(pl) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function artistsToString(artists, max) {
|
||||||
|
var result = '';
|
||||||
|
max = max || 3;
|
||||||
|
for (var i = 0; i < artists.length && i < max; i++) {
|
||||||
|
if (artists[i].name) {
|
||||||
|
if (i > 0) {
|
||||||
|
result += ', ';
|
||||||
|
}
|
||||||
|
result += artists[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************
|
/********************************************************
|
||||||
* break up results and put them in album tables
|
* break up results and put them in album tables
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
@ -488,17 +505,20 @@ function validServiceUri(str) {
|
|||||||
return validUri(str) || isServiceUri(str);
|
return validUri(str) || isServiceUri(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getScheme(uri) {
|
||||||
|
return uri.split(':')[0].toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
function isStreamUri(uri) {
|
function isStreamUri(uri) {
|
||||||
var uriSplit = uri.split(":");
|
|
||||||
var a = validUri(uri);
|
var a = validUri(uri);
|
||||||
var b = radioExtensionsList.indexOf(uriSplit[0].toLowerCase()) >= 0;
|
var b = radioExtensionsList.indexOf(getScheme(uri)) >= 0;
|
||||||
return a || b;
|
return a || b;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMediaClass(uri) {
|
function getMediaClass(uri) {
|
||||||
var uriSplit = uri.split(":")[0].toLowerCase();
|
var scheme = getScheme(uri);
|
||||||
for (var i = 0; i < uriClassList.length; i++) {
|
for (var i = 0; i < uriClassList.length; i++) {
|
||||||
if (uriSplit == uriClassList[i][0]) {
|
if (scheme == uriClassList[i][0]) {
|
||||||
return "fa " + uriClassList[i][1];
|
return "fa " + uriClassList[i][1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,9 +526,9 @@ function getMediaClass(uri) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMediaHuman(uri) {
|
function getMediaHuman(uri) {
|
||||||
var uriSplit = uri.split(":")[0].toLowerCase();
|
var scheme = getScheme(uri);
|
||||||
for (var i = 0; i < uriHumanList.length; i++) {
|
for (var i = 0; i < uriHumanList.length; i++) {
|
||||||
if (uriSplit == uriHumanList[i][0]) {
|
if (scheme == uriHumanList[i][0]) {
|
||||||
return uriHumanList[i][1];
|
return uriHumanList[i][1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -516,19 +536,26 @@ function getMediaHuman(uri) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isServiceUri(uri) {
|
function isServiceUri(uri) {
|
||||||
var uriSplit = uri.split(":")[0].toLowerCase();
|
var scheme = getScheme(uri);
|
||||||
var retVal = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < uriClassList.length; i++) {
|
for (var i = 0; i < uriClassList.length; i++) {
|
||||||
if (uriSplit == uriClassList[i][0]) {
|
if (scheme == uriClassList[i][0]) {
|
||||||
retVal = true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < radioExtensionsList.length; i++) {
|
for (var i = 0; i < radioExtensionsList.length; i++) {
|
||||||
if (uriSplit == radioExtensionsList[i]) {
|
if (scheme == radioExtensionsList[i]) {
|
||||||
retVal = true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retVal;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFavouritesPlaylist(playlist) {
|
||||||
|
return (playlist.name == STREAMS_PLAYLIST_NAME &&
|
||||||
|
getScheme(playlist.uri) == STREAMS_PLAYLIST_SCHEME);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSpotifyStarredPlaylist(playlist) {
|
||||||
|
var starredRegex = /spotify:user:.*:starred/g;
|
||||||
|
return (starredRegex.test(playlist.uri) && playlist.name == 'Starred');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -114,11 +114,11 @@ function setSongInfo(data) {
|
|||||||
|
|
||||||
if(data.track.artists) {
|
if(data.track.artists) {
|
||||||
for (var j = 0; j < data.track.artists.length; j++) {
|
for (var j = 0; j < data.track.artists.length; j++) {
|
||||||
artistshtml += '<a href="#" onclick="return showArtist(\'' + data.track.artists[j].uri + '\');">' + data.track.artists[j].name + '</a>';
|
artistshtml += '<a href="#" onclick="return showArtist(\'' + data.track.artists[j].uri + '\');">' + data.track.artists[j].name + '</a>';
|
||||||
artiststext += data.track.artists[j].name;
|
artiststext += data.track.artists[j].name;
|
||||||
if (j != data.track.artists.length - 1) {
|
if (j != data.track.artists.length - 1) {
|
||||||
artistshtml += ', ';
|
artistshtml += ', ';
|
||||||
artiststext += ', ';
|
artiststext += ', ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
arttmp = artistshtml;
|
arttmp = artistshtml;
|
||||||
@ -224,6 +224,7 @@ function initSocketevents() {
|
|||||||
getCurrentPlaylist();
|
getCurrentPlaylist();
|
||||||
updateStatusOfAll();
|
updateStatusOfAll();
|
||||||
getPlaylists();
|
getPlaylists();
|
||||||
|
showFavourites();
|
||||||
getBrowseDir();
|
getBrowseDir();
|
||||||
getSearchSchemes();
|
getSearchSchemes();
|
||||||
showLoading(false);
|
showLoading(false);
|
||||||
@ -552,7 +553,7 @@ $(document).ready(function(event) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
initStreams();
|
|
||||||
|
|
||||||
if ($(window).width() < 980) {
|
if ($(window).width() < 980) {
|
||||||
$("#panel").panel("close");
|
$("#panel").panel("close");
|
||||||
|
|||||||
@ -159,19 +159,20 @@ function processGetPlaylists(resultArr) {
|
|||||||
if ((!resultArr) || (resultArr == '')) {
|
if ((!resultArr) || (resultArr == '')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var tmp = '',
|
var tmp = '', favourites = '', starred = '';
|
||||||
starredRegex = /spotify:user:.*:starred/g;
|
|
||||||
|
|
||||||
for (var i = 0; i < resultArr.length; i++) {
|
for (var i = 0; i < resultArr.length; i++) {
|
||||||
var li_html = '<li><a href="#" onclick="return showTracklist(this.id);" id="' + resultArr[i].uri + '">';
|
var li_html = '<li><a href="#" onclick="return showTracklist(this.id);" id="' + resultArr[i].uri + '">';
|
||||||
if(starredRegex.test(resultArr[i].uri) && resultArr[i].name == "Starred") {
|
if(isSpotifyStarredPlaylist(resultArr[i])) {
|
||||||
// Prepend the user's Spotify "Starred" playlist to the results (like Spotify official client).
|
starred = li_html + '★ Spotify Starred Tracks</a></li>' + tmp;
|
||||||
tmp = li_html + '★ Spotify Starred Tracks</a></li>' + tmp;
|
} else if (isFavouritesPlaylist(resultArr[i])) {
|
||||||
|
favourites = li_html + '♥ Musicbox Favourites</a></li>';
|
||||||
} else {
|
} else {
|
||||||
// Append everything 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].uri) + '"></i> ' + resultArr[i].name + '</a></li>';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
// Prepend the user's Spotify "Starred" playlist and favourites to the results. (like Spotify official client).
|
||||||
|
tmp = favourites + starred + tmp;
|
||||||
$('#playlistslist').html(tmp);
|
$('#playlistslist').html(tmp);
|
||||||
scrollToTracklist();
|
scrollToTracklist();
|
||||||
showLoading(false);
|
showLoading(false);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user