mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-11 06:53:23 -05:00
Slowly getting playlist editor in shape.
Still readonly, but clickable.
This commit is contained in:
parent
559a45503f
commit
5a17d65d98
@ -10,15 +10,14 @@
|
||||
</head>
|
||||
|
||||
<body @ispage playlist.html:onload="init()":@>
|
||||
|
||||
@ispage playlist.html:<!--:@
|
||||
<div>
|
||||
<!-- <h1>.: m t - d a a p d :.</h1> -->
|
||||
<table border="0" width="100%">
|
||||
<tr><td style="width: 90%;"> </td><td align="center"><img src="mt-daapd.png" alt="mt-daap logo"/>
|
||||
<br />Version @VERSION@</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@ispage playlist.html:-->:@
|
||||
<!-- <hr size="" class="netscape4"> -->
|
||||
<div class="tabs">
|
||||
<a href="index.html" class="@ispage index.html:selected:plain@">Home</a>
|
||||
@ -89,10 +88,10 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- next item -->
|
||||
|
||||
|
||||
</div>
|
||||
</div> <!-- end of box -->
|
||||
</div>
|
||||
|
||||
|
||||
</td>
|
||||
|
@ -933,10 +933,48 @@ table.calendar td.todaynoevent {
|
||||
border: 2px solid #FFA500;
|
||||
}
|
||||
|
||||
.odd {
|
||||
background-color: #ffffff;
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
}
|
||||
.even {
|
||||
background-color: #edf3fe;
|
||||
border-top: 0px;
|
||||
border-bottom: 0px;
|
||||
}
|
||||
.mytbody {
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
font: icon; !important
|
||||
}
|
||||
#browse {
|
||||
font: icon; !important
|
||||
}
|
||||
.mytable {
|
||||
/* The default table for document listings. Contains name, document types, modification times etc in a file-browser-like fashion */
|
||||
border-collapse: collapse;
|
||||
border-left: 1px solid #8CACBB;
|
||||
border-bottom: 1px solid #8CACBB;
|
||||
font-size: 80%;
|
||||
margin: 1em 0em 1em 0em;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.mytable th {
|
||||
background: #DEE7EC;
|
||||
border-top: 1px solid #8CACBB;
|
||||
border-bottom: 1px solid #8CACBB;
|
||||
border-right: 1px solid #8CACBB;
|
||||
color: Black;
|
||||
font-weight: normal;
|
||||
padding: 0em 1em 0em 1em;
|
||||
text-transform: lowercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.mytable td {
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
@include hdr.html@
|
||||
<h1>Playlist</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
@ -10,31 +9,32 @@
|
||||
</td>
|
||||
|
||||
<td valign="top">
|
||||
|
||||
<table id="browse">
|
||||
<tr>
|
||||
<td>
|
||||
Genre<br />
|
||||
<select id="genre" name="select" size="10">
|
||||
<option value="1">All genres</option>
|
||||
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
Artist<br />
|
||||
<select id="artist" name="select" size="10">
|
||||
<option value="1">All artists</option>
|
||||
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
Album<br />
|
||||
<select id="album" name="select" size="10">
|
||||
<option value="1">All albums</option>
|
||||
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="stx" style="break: both;">
|
||||
<table id="songs" border="0" cellspacing="0" cellpadding="0">
|
||||
<div class="" style="break: both;">
|
||||
<table id="songs" class="mytable" border="0" cellspacing="0" cellpadding="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Song</th>
|
||||
@ -44,7 +44,8 @@ Album<br />
|
||||
<th>Genre</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="mytbody">
|
||||
<tr><td></td><td></td><td></td><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -18,56 +18,213 @@
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/* Detta script finns att hämta på http://www.jojoxx.net och
|
||||
får användas fritt så länge som dessa rader står kvar. */
|
||||
|
||||
function DataDumper(obj,n,prefix){
|
||||
var str=""; prefix=(prefix)?prefix:""; n=(n)?n+1:1; var ind=""; for(var i=0;i<n;i++){ ind+=" "; }
|
||||
if(typeof(obj)=="string"){
|
||||
str+=ind+prefix+"String:\""+obj+"\"\n";
|
||||
} else if(typeof(obj)=="number"){
|
||||
str+=ind+prefix+"Number:"+obj+"\n";
|
||||
} else if(typeof(obj)=="function"){
|
||||
str+=ind+prefix+"Function:"+obj+"\n";
|
||||
} else {
|
||||
var type="Array";
|
||||
for(var i in obj){ type=(type=="Array"&&i==parseInt(i))?"Array":"Object" }
|
||||
str+=ind+prefix+type+"[\n";
|
||||
if(type=="Array"){
|
||||
for(var i in obj){ str+=DataDumper(obj[i],n,i+"=>"); }
|
||||
} else {
|
||||
for(var i in obj){ str+=DataDumper(obj[i],n,i+"=>"); }
|
||||
}
|
||||
str+=ind+"]\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
var g_req;
|
||||
var g_requestor;
|
||||
var g_selectedGenres = Array();
|
||||
var g_selectedAlbums = Array();
|
||||
var g_selectedArtists = Array();
|
||||
|
||||
var baseUrl = window.location.toString();
|
||||
baseUrl = baseUrl.substr(0,baseUrl.length-13);
|
||||
String.prototype.myEncodeURI = function () {
|
||||
s = encodeURI(this);
|
||||
s = s.replace(/\'/,'%27');
|
||||
return s.replace(/&/,'%26');
|
||||
};
|
||||
|
||||
function createRequest() {
|
||||
Requestor = function(baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.que = Array();
|
||||
// All browsers but IE
|
||||
g_req = false;
|
||||
if (window.XMLHttpRequest) {
|
||||
g_req = new XMLHttpRequest();
|
||||
g_req = false;
|
||||
if (window.XMLHttpRequest) {
|
||||
g_req = new XMLHttpRequest();
|
||||
// MS IE
|
||||
} else if (window.ActiveXObject) {
|
||||
g_req = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
} else if (window.ActiveXObject) {
|
||||
g_req = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
this.busy = false;
|
||||
|
||||
};
|
||||
Requestor.prototype.addRequest = function(url) {
|
||||
if (this.busy) {
|
||||
this.que.push(url);
|
||||
} else {
|
||||
this._openRequest(url);
|
||||
}
|
||||
};
|
||||
|
||||
Requestor.prototype._openRequest = function(url) {
|
||||
this.busy = true;
|
||||
if (url.search(/\?/)> -1) {
|
||||
url += '&output=xml';
|
||||
} else {
|
||||
url += '?output=xml';
|
||||
}
|
||||
g_req.open('get',this.baseUrl+url,true);
|
||||
g_req.onreadystatechange = Requestor_handleRequest;
|
||||
g_req.send(null);
|
||||
};
|
||||
Requestor_handleRequest = function() {
|
||||
if (4 == g_req.readyState) {
|
||||
// readystate 4 means the whole document is loaded
|
||||
if (200 == g_req.status) {
|
||||
// Only try to parse the response if we got
|
||||
// ok from the server
|
||||
xmldoc = g_req.responseXML;
|
||||
if ('daap.databaseplaylists' == xmldoc.firstChild.nodeName) {
|
||||
el = document.getElementById('source');
|
||||
addPlaylists(el,xmldoc);
|
||||
} else if ('daap.databasebrowse' == xmldoc.firstChild.nodeName) {
|
||||
// Ok we have response from a browse query
|
||||
|
||||
switch (xmldoc.firstChild.childNodes[3].nodeName) {
|
||||
case 'daap.browsegenrelisting':
|
||||
el = document.getElementById('genre');
|
||||
addOptions(el,'genre',xmldoc);
|
||||
break;
|
||||
case 'daap.browseartistlisting':
|
||||
el = document.getElementById('artist');
|
||||
addOptions(el,'artist',xmldoc);
|
||||
break;
|
||||
case 'daap.browsealbumlisting':
|
||||
el = document.getElementById('album');
|
||||
addOptions(el,'album',xmldoc);
|
||||
break;
|
||||
default:
|
||||
// We got something else back...
|
||||
}
|
||||
} else if ('daap.databasesongs' == xmldoc.firstChild.nodeName) {
|
||||
// Songlist
|
||||
addSongs(xmldoc);
|
||||
}
|
||||
}
|
||||
if (g_requestor.que.length > 0) {
|
||||
// Just to be able to pull ourseves up by our boot straps
|
||||
window.setTimeout(Requestor_queChecker,5);
|
||||
return;
|
||||
} else {
|
||||
g_requestor.busy = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
function Requestor_queChecker() {
|
||||
if (url = g_requestor.que.shift()) {
|
||||
g_requestor._openRequest(url);
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
g_requestor = new Requestor(baseUrl);
|
||||
g_requestor.addRequest('databases/1/containers');
|
||||
g_requestor.addRequest('databases/1/browse/genres');
|
||||
g_requestor.addRequest('databases/1/browse/artists');
|
||||
g_requestor.addRequest('databases/1/browse/albums');
|
||||
el = document.getElementById('source');
|
||||
el.addEventListener('change',playlistSelect,true);
|
||||
|
||||
el = document.getElementById('genre');
|
||||
el.addEventListener('change',genreSelect,true);
|
||||
|
||||
el = document.getElementById('artist');
|
||||
el.addEventListener('change',artistSelect,true);
|
||||
|
||||
//###FIXME album select
|
||||
return;
|
||||
// get playlists
|
||||
createRequest();
|
||||
//alert(baseUrl+'databases/1/browse/genres?output=xml');
|
||||
|
||||
g_req.open('get',baseUrl+'databases/1/containers?output=xml',false);
|
||||
g_req.send(null);
|
||||
el = document.getElementById('source');
|
||||
addPlaylists(el,g_req.responseXML);
|
||||
el.addEventListener('change',playlistSelect,true);
|
||||
|
||||
|
||||
g_req.open('get',baseUrl+'databases/1/browse/genres?output=xml',false);
|
||||
g_req.send(null);
|
||||
el = document.getElementById('genre');
|
||||
addOptions(el,g_req.responseXML);
|
||||
|
||||
|
||||
g_req.open('get',baseUrl+'databases/1/browse/artists?output=xml',false);
|
||||
g_req.send(null);
|
||||
el = document.getElementById('artist');
|
||||
addOptions(el,g_req.responseXML);
|
||||
|
||||
|
||||
g_req.open('get',baseUrl+'databases/1/browse/albums?output=xml',false);
|
||||
g_req.send(null);
|
||||
el = document.getElementById('album');
|
||||
addOptions(el,g_req.responseXML);
|
||||
addOptions(el,'album',g_req.responseXML);
|
||||
|
||||
}
|
||||
function addOptions(el,xmldoc) {
|
||||
function addOptions(el,label,xmldoc) {
|
||||
while(el.hasChildNodes()) {
|
||||
el.removeChild(el.firstChild);
|
||||
}
|
||||
itemCnt = xmldoc.getElementsByTagName('dmap.specifiedtotalcount').item(0).textContent;
|
||||
if (parseInt(itemCnt) > 1) {
|
||||
plural = 's';
|
||||
} else {
|
||||
plural = '';
|
||||
}
|
||||
option = document.createElement('option');
|
||||
option.value = '1';
|
||||
option.selected = false;
|
||||
option.appendChild(document.createTextNode('All ('+itemCnt+' '+label +plural+')'));
|
||||
el.appendChild(option);
|
||||
|
||||
items = xmldoc.getElementsByTagName('dmap.listingitem');
|
||||
for (i=0; i<items.length; i++) {
|
||||
option = document.createElement('option');
|
||||
option.setAttribute('value',items[i].firstChild.nodeValue);
|
||||
option.appendChild(document.createTextNode(items[i].textContent));
|
||||
itemName = items[i].textContent;
|
||||
option.value = itemName;
|
||||
selectAll = true;
|
||||
switch (label) {
|
||||
case 'genre':
|
||||
if (g_selectedGenres[itemName]) {
|
||||
//option.selected = true;
|
||||
selectAll = false;
|
||||
}
|
||||
break;
|
||||
case 'artist':
|
||||
if (g_selectedArtists[itemName]) {
|
||||
//option.selected = true;
|
||||
selectAll = false;
|
||||
}
|
||||
case 'album':
|
||||
if (g_selectedAlbums[itemName]) {
|
||||
//option.selected = true;
|
||||
selectAll = false;
|
||||
}
|
||||
default: // if we get here something is wrong
|
||||
// silently ignore it
|
||||
}
|
||||
//###FIXME do some kind of itelligent truncation of the string
|
||||
option.appendChild(document.createTextNode(itemName.substr(0,30)));
|
||||
el.appendChild(option);
|
||||
}
|
||||
if (selectAll) {
|
||||
el.options[0].selected = true;
|
||||
} else {
|
||||
el.removeAttribute('selected');
|
||||
}
|
||||
}
|
||||
function addPlaylists(el,xmldoc) {
|
||||
//items = xmldoc.getElementsByTagName('dmap.listingitem');
|
||||
@ -82,7 +239,6 @@ function addPlaylists(el,xmldoc) {
|
||||
el.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
function playlistSelect(event) {
|
||||
table = document.getElementById('songs');
|
||||
tableBody = removeRows(table);
|
||||
@ -98,7 +254,7 @@ function playlistSelect(event) {
|
||||
g_req.send(null);
|
||||
|
||||
items = g_req.responseXML.getElementsByTagName('dmap.listingitem');
|
||||
|
||||
className = 'odd';
|
||||
for (i=0; i < items.length; i++) {
|
||||
// Have to check if the tag really was returned from the server
|
||||
if (song = items[i].getElementsByTagName('dmap.itemname').item(0)) {
|
||||
@ -122,12 +278,18 @@ function playlistSelect(event) {
|
||||
} else {
|
||||
genre = '';
|
||||
}
|
||||
addRow(tableBody,song,time,artist,album,genre);
|
||||
if ('odd' == className) {
|
||||
className = 'even';
|
||||
} else {
|
||||
className = 'odd';
|
||||
}
|
||||
addRow(tableBody,className,song,time,artist,album,genre);
|
||||
}
|
||||
|
||||
}
|
||||
function addRow(tbody,song,time,artist,album,genre) {
|
||||
function addRow(tbody,className,song,time,artist,album,genre) {
|
||||
row = document.createElement("tr");
|
||||
row.setAttribute('class',className);
|
||||
cell = document.createElement("td");
|
||||
cell.appendChild(document.createTextNode(song));
|
||||
row.appendChild(cell);
|
||||
@ -137,7 +299,8 @@ function addRow(tbody,song,time,artist,album,genre) {
|
||||
row.appendChild(cell);
|
||||
|
||||
cell = document.createElement("td");
|
||||
cell.appendChild(document.createTextNode(artist));
|
||||
//###FIXME do some kind of itelligent truncation of the string
|
||||
cell.appendChild(document.createTextNode(artist.substring(0,30)));
|
||||
row.appendChild(cell);
|
||||
|
||||
cell = document.createElement("td");
|
||||
@ -154,6 +317,131 @@ function removeRows(table) {
|
||||
tableBody = table.getElementsByTagName('tbody').item(0);
|
||||
table.removeChild(tableBody);
|
||||
tableBody = document.createElement('tbody');
|
||||
tableBody.setAttribute('class','mytbody');
|
||||
table.appendChild(tableBody);
|
||||
return tableBody;
|
||||
}
|
||||
function genreSelect(event) {
|
||||
selectObject = event.target;
|
||||
if (selectObject.options[0].selected) {
|
||||
filter = '';
|
||||
g_selectedGenres = Array();
|
||||
//###FIXME must dselect all others
|
||||
} else {
|
||||
filter = Array();
|
||||
//###FIXME if there is just the all genre there will be an error here
|
||||
for (i=1; i<selectObject.options.length; i++) {
|
||||
genre = selectObject.options[i].value;
|
||||
if (selectObject.options[i].selected) {
|
||||
filter.push("'daap.songgenre:" + genre.myEncodeURI() + "'");
|
||||
g_selectedGenres[genre] = true;
|
||||
} else {
|
||||
g_selectedGenres[genre] = false;
|
||||
}
|
||||
}
|
||||
filter = '?filter=' + filter.join(',');
|
||||
}
|
||||
g_requestor.addRequest('databases/1/browse/artists' + filter);
|
||||
g_requestor.addRequest('databases/1/browse/albums' + filter);
|
||||
getSongs();
|
||||
}
|
||||
|
||||
function artistSelect(event) {
|
||||
selectObject = event.target;
|
||||
filter = '';
|
||||
if (selectObject.options[0].selected) {
|
||||
// All selected, sort according to genre
|
||||
filter = Array();
|
||||
for (genre in g_selectedGenres) {
|
||||
if (g_selectedGenres[genre]) {
|
||||
filter.push("'daap.songgenre:" + genre.myEncodeURI() + "'");
|
||||
}
|
||||
}
|
||||
if (0 == filter.length) {
|
||||
// If filter array is empty then "All genres" is selected
|
||||
// so set filter to empty
|
||||
filter = '';
|
||||
} else {
|
||||
filter = '?filter=' + filter.join(',');
|
||||
}
|
||||
} else {
|
||||
filter = Array();
|
||||
for (i=1; i<selectObject.options.length; i++) {
|
||||
artist = selectObject.options[i].value;
|
||||
if (selectObject.options[i].selected) {
|
||||
filter.push("'daap.songartist:" + artist.myEncodeURI() + "'");
|
||||
g_selectedArtists[artist] = true;
|
||||
} else {
|
||||
g_selectedArtists[artist] = false;
|
||||
}
|
||||
}
|
||||
// If all is selected then search on all artists but honor genre
|
||||
filter = '?filter=' + filter.join(',');
|
||||
}
|
||||
g_requestor.addRequest('databases/1/browse/albums' + filter);
|
||||
getSongs();
|
||||
}
|
||||
function getSongs() {
|
||||
genre = document.getElementById('genre').value;
|
||||
artist = document.getElementById('artist').value;
|
||||
album = document.getElementById('album').value;
|
||||
query = Array();
|
||||
if (genre != '1') {
|
||||
query.push('\'daap.songgenre:' + genre +"'");
|
||||
}
|
||||
if (artist != '1') {
|
||||
query.push('\'daap.songartist:' + artist +"'");
|
||||
}
|
||||
if (album != '1') {
|
||||
query.push('\'daap.songalbum:' + album +"'");
|
||||
}
|
||||
if (0 == filter.length) {
|
||||
// If filter array is empty then "All genres" is selected
|
||||
// so set filter to empty
|
||||
query = '';
|
||||
} else {
|
||||
query = '&query=' + query.join(',');
|
||||
}
|
||||
g_requestor.addRequest('databases/1/items' +
|
||||
'?meta=dmap.itemname,daap.songalbum,daap.songartist,daap.songgenre,daap.songtime'+query);
|
||||
///items?meta=dmap.itemname,daap.songalbum,daap.songartist,daap.songgenre,daap.songtime&output=xml
|
||||
|
||||
}
|
||||
function addSongs(xmldoc) {
|
||||
items = xmldoc.getElementsByTagName('dmap.listingitem');
|
||||
className = 'odd';
|
||||
table = document.getElementById('songs');
|
||||
tableBody = removeRows(table);
|
||||
|
||||
for (i=0; i < items.length; i++) {
|
||||
// Have to check if the tag really was returned from the server
|
||||
if (song = items[i].getElementsByTagName('dmap.itemname').item(0)) {
|
||||
song = song.textContent;
|
||||
} else {
|
||||
song = '';
|
||||
}
|
||||
time = ''; //items[i].getElementsByTagName('daap.songtime').item(0).textContent;
|
||||
if (artist = items[i].getElementsByTagName('daap.songartist').item(0)) {
|
||||
artist = artist.textContent;
|
||||
} else {
|
||||
artist = '';
|
||||
}
|
||||
if (album = items[i].getElementsByTagName('daap.songalbum').item(0)) {
|
||||
album = album.textContent;
|
||||
} else {
|
||||
album = '';
|
||||
}
|
||||
if (genre = items[i].getElementsByTagName('daap.songgenre').item(0)) {
|
||||
genre = genre.textContent;
|
||||
} else {
|
||||
genre = '';
|
||||
}
|
||||
if ('odd' == className) {
|
||||
className = 'even';
|
||||
} else {
|
||||
className = 'odd';
|
||||
}
|
||||
addRow(tableBody,className,song,time,artist,album,genre);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user