mirror of
https://github.com/SuperBFG7/ympd
synced 2024-12-26 11:00:27 +00:00
Feat: Add playlist actions
This commit is contained in:
parent
c8895ebdd8
commit
c403202c7d
@ -213,3 +213,10 @@ div.alertBoxActive {
|
||||
.opacity05 {
|
||||
opacity:0.5;
|
||||
}
|
||||
|
||||
caption {
|
||||
caption-side: top;
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
}
|
||||
|
@ -195,6 +195,14 @@
|
||||
|
||||
<div class="card-body hide" id="cardBrowsePlaylists">
|
||||
<div class="btn-toolbar card-toolbar" id="BrowsePlaylistsButtons" role="toolbar">
|
||||
<div class="btn-group mr-2 hide">
|
||||
<button data-href="{'cmd': 'appGoto', 'options': ['Browse','Playlists','All']}" id="btnBrowsePlaylistsAll" type="button" class="btn btn-secondary">« Playlists</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2 hide">
|
||||
<button id="btnPlaylistClear" type="button" class="btn btn-secondary" data-href="{'cmd': 'playlistClear', 'options': []}" title="Clear playlist">
|
||||
<span class="material-icons">clear_all</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2">
|
||||
<button id="BrowsePlaylistsFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
|
||||
<div class="dropdown-menu bg-dark px-2 letters" id="BrowsePlaylistsFilterLetters">
|
||||
@ -210,9 +218,8 @@
|
||||
<button data-href="{'cmd': 'gotoPage', 'options': ['next']}" id="BrowsePlaylistsPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive-md">
|
||||
<table id="BrowsePlaylistsList" class="table table-hover table-sm">
|
||||
<table id="BrowsePlaylistsAllList" class="table table-hover table-sm">
|
||||
<col class="tblnum"/>
|
||||
<col class="tbltitle"/>
|
||||
<col class="tbllastmodified"/>
|
||||
@ -228,6 +235,27 @@
|
||||
<tbody class="clickable">
|
||||
</tbody>
|
||||
</table>
|
||||
<table id="BrowsePlaylistsDetailList" class="table table-hover table-sm hide">
|
||||
<caption>Playlist List</caption>
|
||||
<col class="tblnum"/>
|
||||
<col class="tbltitle"/>
|
||||
<col class="tblartist"/>
|
||||
<col class="tblalbum"/>
|
||||
<col class="tbllength"/>
|
||||
<col class="tblaction"/>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Title</th>
|
||||
<th>Artist</th>
|
||||
<th>Album</th>
|
||||
<th>Duration</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="clickable">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="btn-toolbar" id="BrowsePlaylistsButtonsBottom" role="toolbar">
|
||||
<div class="btn-group mr-2">
|
||||
@ -248,10 +276,9 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body hide" id="cardBrowseDatabase">
|
||||
|
||||
<div class="btn-toolbar card-toolbar" id="BrowseDatabaseButtons" role="toolbar">
|
||||
<div class="btn-group mr-2">
|
||||
<button data-href="{'cmd': 'appGoto', 'options': ['Browse','Database','Artist']}" id="btnBrowseDatabaseArtist" type="button" class="btn btn-secondary hide">« Artists</button>
|
||||
<div class="btn-group mr-2 hide">
|
||||
<button data-href="{'cmd': 'appGoto', 'options': ['Browse','Database','Artist']}" id="btnBrowseDatabaseArtist" type="button" class="btn btn-secondary">« Artists</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2">
|
||||
<button id="BrowseDatabaseFilter" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">Filter</button>
|
||||
@ -286,7 +313,7 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="BrowseDatabaseAlbumCards" class="row"></div>
|
||||
<div id="BrowseDatabaseAlbumCards" class="row hide"></div>
|
||||
|
||||
<div class="btn-toolbar" id="BrowseDatabaseButtonsBottom" role="toolbar">
|
||||
<div class="btn-group mr-2">
|
||||
@ -462,8 +489,8 @@
|
||||
</nav>
|
||||
</footer>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal" id="modalConnectionError" role="dialog">
|
||||
<!-- Modals -->
|
||||
<div class="modal fade" id="modalConnectionError" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-light">
|
||||
@ -476,7 +503,59 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modalAddToPlaylist" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">playlist_add</span> Add to playlist</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="addToPlaylistFrm">
|
||||
<input type="hidden" id="addToPlaylistUri"/>
|
||||
<div class="form-group input-group col-md-6 border-secondary">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text bg-secondary text-light border-secondary">Playlist</div>
|
||||
</div>
|
||||
<select id="addToPlaylistPlaylist" class="form-control custom-select border-secondary">
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-href="{'cmd': 'addToPlaylist', 'options': []}">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalRenamePlaylist" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><span class="material-icons title-icon">playlist_add</span>Rename playlist</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="needs-validation" id="renamePlaylistFrm" novalidate>
|
||||
<div class="form-group">
|
||||
<label for="fromInput">From</label>
|
||||
<input type="text" class="form-control" id="renamePlaylistFrom" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="renamePlaylistTo">To</label>
|
||||
<input type="text" class="form-control" id="renamePlaylistTo">
|
||||
<div class="invalid-feedback">Invalid filename.</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-href="{'cmd': 'renamePlaylist', 'options': []}">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalSettings" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@ -570,7 +649,6 @@
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modalAbout" tabindex="-1" role="dialog" aria-labelledby="settingsLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
@ -608,7 +686,6 @@
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="modalAddstream" tabindex="-1" role="dialog" aria-labelledby="addstreamLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
273
htdocs/js/mpd.js
273
htdocs/js/mpd.js
@ -38,7 +38,12 @@ app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Browse": {
|
||||
"active": "Database",
|
||||
"tabs": { "Filesystem": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Playlists": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Playlists": {
|
||||
"active": "All",
|
||||
"views": { "All": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Detail": { "state": "0/-/", "scrollPos": 0 }
|
||||
}
|
||||
},
|
||||
"Database": {
|
||||
"active": "Artist",
|
||||
"views": { "Artist": { "state": "0/-/", "scrollPos": 0 },
|
||||
@ -75,6 +80,8 @@ var modalSettings = new Modal(document.getElementById('modalSettings'));
|
||||
var modalAddstream = new Modal(document.getElementById('modalAddstream'));
|
||||
var modalSavequeue = new Modal(document.getElementById('modalSavequeue'));
|
||||
var modalSongDetails = new Modal(document.getElementById('modalSongDetails'));
|
||||
var modalAddToPlaylist = new Modal(document.getElementById('modalAddToPlaylist'));
|
||||
var modalRenamePlaylist = new Modal(document.getElementById('modalRenamePlaylist'));
|
||||
var mainMenu = new Dropdown(document.getElementById('mainMenu'));
|
||||
|
||||
function appPrepare(scrollPos) {
|
||||
@ -102,6 +109,11 @@ function appPrepare(scrollPos) {
|
||||
}
|
||||
scrollTo(scrollPos);
|
||||
}
|
||||
var list = document.getElementById(app.current.app +
|
||||
(app.current.tab == undefined ? '' : app.current.tab) +
|
||||
(app.current.view == undefined ? '' : app.current.view) + 'List');
|
||||
if (list)
|
||||
list.classList.add('opacity05');
|
||||
}
|
||||
|
||||
function appGoto(a,t,v,s) {
|
||||
@ -171,13 +183,6 @@ function appRoute() {
|
||||
sendAPI({"cmd":"MPD_API_GET_CURRENT_SONG"}, songChange);
|
||||
}
|
||||
else if (app.current.app == 'Queue' ) {
|
||||
document.getElementById('QueueList').classList.add('opacity05');
|
||||
/* if (app.last.app != app.current.app) {
|
||||
if (app.current.search.length < 2) {
|
||||
setPagination(app.current.page);
|
||||
}
|
||||
}
|
||||
*/
|
||||
var btns = document.getElementById('searchqueuetag').getElementsByTagName('button');
|
||||
for (var i = 0; i < btns.length; i++) {
|
||||
btns[i].classList.remove('active');
|
||||
@ -188,23 +193,23 @@ function appRoute() {
|
||||
}
|
||||
getQueue();
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists') {
|
||||
document.getElementById('BrowsePlaylistsList').classList.add('opacity05');
|
||||
sendAPI({"cmd":"MPD_API_GET_PLAYLISTS","data": {"offset": app.current.page, "filter": app.current.filter}},parsePlaylists);
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') {
|
||||
sendAPI({"cmd":"MPD_API_GET_PLAYLISTS","data": {"offset": app.current.page, "filter": app.current.filter}}, parsePlaylists);
|
||||
doSetFilterLetter('BrowsePlaylistsFilter');
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'Detail') {
|
||||
sendAPI({"cmd":"MPD_API_GET_PLAYLIST_LIST","data": {"offset": app.current.page, "filter": app.current.filter, "uri": app.current.search}}, parsePlaylists);
|
||||
doSetFilterLetter('BrowsePlaylistsFilter');
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Database' && app.current.view == 'Artist') {
|
||||
document.getElementById('BrowseDatabaseArtistList').classList.add('opacity05');
|
||||
sendAPI({"cmd":"MPD_API_GET_ARTISTS","data": {"offset": app.current.page, "filter": app.current.filter}}, parseListDBtags);
|
||||
doSetFilterLetter('BrowseDatabaseFilter');
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Database' && app.current.view == 'Album') {
|
||||
document.getElementById('BrowseDatabaseAlbumCards').classList.add('opacity05');
|
||||
sendAPI({"cmd":"MPD_API_GET_ARTISTALBUMS","data": {"offset": app.current.page, "filter": app.current.filter, "albumartist": app.current.search}}, parseListDBtags);
|
||||
doSetFilterLetter('BrowseDatabaseFilter');
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Filesystem') {
|
||||
document.getElementById('BrowseFilesystemList').classList.add('opacity05');
|
||||
sendAPI({"cmd":"MPD_API_GET_FILESYSTEM","data": {"offset": app.current.page, "path": (app.current.search ? app.current.search : "/"), "filter": app.current.filter}}, parseFilesystem);
|
||||
// Don't add all songs from root
|
||||
if (app.current.search)
|
||||
@ -238,15 +243,11 @@ function appRoute() {
|
||||
}
|
||||
else if (app.current.app == 'Search') {
|
||||
document.getElementById('searchstr').focus();
|
||||
document.getElementById('SearchList').classList.add('opacity05');
|
||||
if (app.last.app != app.current.app) {
|
||||
if (app.current.search != '')
|
||||
document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML=
|
||||
'<tr><td><span class="material-icons">search</span></td>' +
|
||||
'<td colspan="5">Searching...</td></tr>';
|
||||
// else
|
||||
// setPagination(app.current.page);
|
||||
// document.getElementById('searchstr').value = app.current.search;
|
||||
}
|
||||
|
||||
if (app.current.search.length >= 2) {
|
||||
@ -255,7 +256,6 @@ function appRoute() {
|
||||
document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML = '';
|
||||
document.getElementById('searchAddAllSongs').setAttribute('disabled', 'disabled');
|
||||
document.getElementById('panel-heading-search').innerText = '';
|
||||
// setPagination(app.current.page);
|
||||
document.getElementById('SearchList').classList.remove('opacity05');
|
||||
}
|
||||
|
||||
@ -313,10 +313,6 @@ function appInit() {
|
||||
document.getElementById('streamurl').focus();
|
||||
});
|
||||
|
||||
document.getElementById('addstreamFrm').addEventListener('submit', function () {
|
||||
addStream();
|
||||
});
|
||||
|
||||
addFilterLetter('BrowseFilesystemFilterLetters');
|
||||
addFilterLetter('BrowseDatabaseFilterLetters');
|
||||
addFilterLetter('BrowsePlaylistsFilterLetters');
|
||||
@ -386,7 +382,17 @@ function appInit() {
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('BrowsePlaylistsList').addEventListener('click', function(event) {
|
||||
document.getElementById('BrowsePlaylistsAllList').addEventListener('click', function(event) {
|
||||
if (event.target.nodeName == 'TD') {
|
||||
appendQueue('plist', decodeURI(event.target.parentNode.getAttribute("data-uri")), event.target.parentNode.getAttribute("data-name"));
|
||||
}
|
||||
else if (event.target.nodeName == 'A') {
|
||||
event.preventDefault();
|
||||
showMenu(event.target);
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('BrowsePlaylistsDetailList').addEventListener('click', function(event) {
|
||||
if (event.target.nodeName == 'TD') {
|
||||
appendQueue('plist', decodeURI(event.target.parentNode.getAttribute("data-uri")), event.target.parentNode.getAttribute("data-name"));
|
||||
}
|
||||
@ -877,23 +883,23 @@ function parseFilesystem(obj) {
|
||||
switch(obj.data[i].type) {
|
||||
case 'dir':
|
||||
row.innerHTML = '<td><span class="material-icons">folder_open</span></td>' +
|
||||
'<td colspan="4">' + obj.data[i].name + '</td>' +
|
||||
'<td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
'<td colspan="4">' + obj.data[i].name + '</td>' +
|
||||
'<td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
break;
|
||||
case 'song':
|
||||
var minutes = Math.floor(obj.data[i].duration / 60);
|
||||
var seconds = obj.data[i].duration - minutes * 60;
|
||||
row.innerHTML = '<td><span class="material-icons">music_note</span></td>' +
|
||||
'<td>' + obj.data[i].title + '</td>' +
|
||||
'<td>' + obj.data[i].artist + '</td>' +
|
||||
'<td>' + obj.data[i].album + '</td>' +
|
||||
'<td>' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds +
|
||||
'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
'<td>' + obj.data[i].title + '</td>' +
|
||||
'<td>' + obj.data[i].artist + '</td>' +
|
||||
'<td>' + obj.data[i].album + '</td>' +
|
||||
'<td>' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds +
|
||||
'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
break;
|
||||
case 'plist':
|
||||
row.innerHTML = '<td><span class="material-icons">list</span></td>' +
|
||||
'<td colspan="4">' + obj.data[i].name + '</td>' +
|
||||
'<td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
'<td colspan="4">' + obj.data[i].name + '</td>' +
|
||||
'<td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
break;
|
||||
}
|
||||
if (i < tr.length)
|
||||
@ -917,28 +923,76 @@ function parseFilesystem(obj) {
|
||||
function parsePlaylists(obj) {
|
||||
if (app.current.app !== 'Browse' && app.current.tab !== 'Playlists')
|
||||
return;
|
||||
if (app.current.view == 'All') {
|
||||
document.getElementById('BrowsePlaylistsAllList').classList.remove('hide');
|
||||
document.getElementById('BrowsePlaylistsDetailList').classList.add('hide');
|
||||
document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.add('hide');
|
||||
document.getElementById('btnPlaylistClear').parentNode.classList.add('hide');
|
||||
} else {
|
||||
if (obj.uri.indexOf('.') > -1) {
|
||||
document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-ro', 'true')
|
||||
document.getElementById('btnPlaylistClear').parentNode.classList.add('hide');
|
||||
}
|
||||
else {
|
||||
document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-ro', 'false');
|
||||
document.getElementById('btnPlaylistClear').parentNode.classList.remove('hide');
|
||||
}
|
||||
document.getElementById('BrowsePlaylistsDetailList').setAttribute('data-uri', obj.uri);
|
||||
document.getElementById('BrowsePlaylistsDetailList').getElementsByTagName('caption')[0].innerText = 'Playlist: ' + obj.uri;
|
||||
document.getElementById('BrowsePlaylistsDetailList').classList.remove('hide');
|
||||
document.getElementById('BrowsePlaylistsAllList').classList.add('hide');
|
||||
document.getElementById('btnBrowsePlaylistsAll').parentNode.classList.remove('hide');
|
||||
}
|
||||
|
||||
var nrItems = obj.data.length;
|
||||
var tbody = document.getElementById(app.current.app + app.current.tab + 'List').getElementsByTagName('tbody')[0];
|
||||
var tbody = document.getElementById(app.current.app + app.current.tab + app.current.view + 'List').getElementsByTagName('tbody')[0];
|
||||
var tr = tbody.getElementsByTagName('tr');
|
||||
for (var i = 0; i < nrItems; i++) {
|
||||
var uri = encodeURI(obj.data[i].uri);
|
||||
if (tr[i])
|
||||
if (tr[i].getAttribute('data-uri') == uri)
|
||||
continue;
|
||||
var d = new Date(obj.data[i].last_modified * 1000);
|
||||
var row = document.createElement('tr');
|
||||
row.setAttribute('data-uri', uri);
|
||||
row.setAttribute('data-type', 'plist');
|
||||
row.setAttribute('data-name', obj.data[i].name);
|
||||
row.innerHTML = '<td><span class="material-icons">list</span></td>' +
|
||||
'<td>' + obj.data[i].name + '</td>' +
|
||||
'<td>'+ d.toUTCString() + '</td>' +
|
||||
'<td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
if (i < tr.length)
|
||||
tr[i].replaceWith(row);
|
||||
else
|
||||
tbody.append(row);
|
||||
if (app.current.view == 'All') {
|
||||
for (var i = 0; i < nrItems; i++) {
|
||||
var uri = encodeURI(obj.data[i].uri);
|
||||
if (tr[i])
|
||||
if (tr[i].getAttribute('data-uri') == uri)
|
||||
continue;
|
||||
var d = new Date(obj.data[i].last_modified * 1000);
|
||||
var row = document.createElement('tr');
|
||||
row.setAttribute('data-uri', uri);
|
||||
row.setAttribute('data-type', 'plist');
|
||||
row.setAttribute('data-name', obj.data[i].name);
|
||||
row.innerHTML = '<td><span class="material-icons">list</span></td>' +
|
||||
'<td>' + obj.data[i].name + '</td>' +
|
||||
'<td>'+ d.toUTCString() + '</td>' +
|
||||
'<td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
if (i < tr.length)
|
||||
tr[i].replaceWith(row);
|
||||
else
|
||||
tbody.append(row);
|
||||
}
|
||||
}
|
||||
else if (app.current.view == 'Detail') {
|
||||
for (var i = 0; i < nrItems; i++) {
|
||||
var uri = encodeURI(obj.data[i].uri);
|
||||
if (tr[i])
|
||||
if (tr[i].getAttribute('data-uri') == uri)
|
||||
continue;
|
||||
var songpos = obj.offset + i;
|
||||
var row = document.createElement('tr');
|
||||
row.setAttribute('data-type', obj.data[i].type);
|
||||
row.setAttribute('data-uri', uri);
|
||||
row.setAttribute('data-name', obj.data[i].name);
|
||||
row.setAttribute('data-songpos', songpos);
|
||||
var minutes = Math.floor(obj.data[i].duration / 60);
|
||||
var seconds = obj.data[i].duration - minutes * 60;
|
||||
row.innerHTML = '<td>' + (songpos + 1) + '</td>' +
|
||||
'<td>' + obj.data[i].title + '</td>' +
|
||||
'<td>' + obj.data[i].artist + '</td>' +
|
||||
'<td>' + obj.data[i].album + '</td>' +
|
||||
'<td>' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds +
|
||||
'</td><td><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
if (i < tr.length)
|
||||
tr[i].replaceWith(row);
|
||||
else
|
||||
tbody.append(row);
|
||||
}
|
||||
}
|
||||
var tr_length=tr.length - 1;
|
||||
for (var i = tr_length; i >= nrItems; i --) {
|
||||
@ -948,9 +1002,14 @@ function parsePlaylists(obj) {
|
||||
setPagination(obj.totalEntities);
|
||||
|
||||
if (nrItems == 0)
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="5">No playlists found.</td></tr>'
|
||||
document.getElementById(app.current.app + (app.current.tab==undefined ? '' : app.current.tab) + 'List').classList.remove('opacity05');
|
||||
if (app.current.view == 'All')
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="5">No playlists found.</td></tr>';
|
||||
else
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="5">Empty playlist.</td></tr>';
|
||||
|
||||
document.getElementById(app.current.app + app.current.tab + app.current.view + 'List').classList.remove('opacity05');
|
||||
}
|
||||
|
||||
function parseListDBtags(obj) {
|
||||
@ -959,7 +1018,7 @@ function parseListDBtags(obj) {
|
||||
if (obj.tagtype == 'AlbumArtist') {
|
||||
document.getElementById('BrowseDatabaseAlbumCards').classList.add('hide');
|
||||
document.getElementById('BrowseDatabaseArtistList').classList.remove('hide');
|
||||
document.getElementById('btnBrowseDatabaseArtist').classList.add('hide');
|
||||
document.getElementById('btnBrowseDatabaseArtist').parentNode.classList.add('hide');
|
||||
var nrItems = obj.data.length;
|
||||
var tbody = document.getElementById(app.current.app + app.current.tab + app.current.view + 'List').getElementsByTagName('tbody')[0];
|
||||
var tr = tbody.getElementsByTagName('tr');
|
||||
@ -994,7 +1053,7 @@ function parseListDBtags(obj) {
|
||||
} else if (obj.tagtype == 'Album') {
|
||||
document.getElementById('BrowseDatabaseAlbumCards').classList.remove('hide');
|
||||
document.getElementById('BrowseDatabaseArtistList').classList.add('hide');
|
||||
document.getElementById('btnBrowseDatabaseArtist').classList.remove('hide');
|
||||
document.getElementById('btnBrowseDatabaseArtist').parentNode.classList.remove('hide');
|
||||
var nrItems = obj.data.length;
|
||||
var cardContainer = document.getElementById('BrowseDatabaseAlbumCards');
|
||||
var cards = cardContainer.querySelectorAll('.col-md');
|
||||
@ -1178,6 +1237,74 @@ function parseSongDetails(obj) {
|
||||
}
|
||||
}
|
||||
|
||||
function playlistDetails(uri) {
|
||||
appGoto('Browse', 'Playlists', 'Detail', '0/-/' + uri);
|
||||
}
|
||||
|
||||
function removeFromPlaylist(uri, pos) {
|
||||
sendAPI({"cmd": "MPD_API_RM_PLAYLIST_TRACK", "data": {"uri": uri, "track": pos}});
|
||||
document.getElementById('BrowsePlaylistsDetailList').classList.add('opacity05');
|
||||
sendAPI({"cmd": "MPD_API_GET_PLAYLIST_LIST", "data": {"offset": app.current.page, "filter": app.current.filter, "uri": app.current.search}}, parsePlaylists);
|
||||
}
|
||||
|
||||
function playlistClear() {
|
||||
var uri = document.getElementById('BrowsePlaylistsDetailList').getAttribute('data-uri');
|
||||
sendAPI({"cmd": "MPD_API_PLAYLIST_CLEAR", "data": {"uri": uri}});
|
||||
document.getElementById('BrowsePlaylistsDetailList').classList.add('opacity05');
|
||||
sendAPI({"cmd": "MPD_API_GET_PLAYLIST_LIST", "data": {"offset": app.current.page, "filter": app.current.filter, "uri": app.current.search}}, parsePlaylists);
|
||||
}
|
||||
|
||||
function getAllPlaylists(obj) {
|
||||
var nrItems = obj.data.length;
|
||||
var playlists = '';
|
||||
for (var i = 0; i < nrItems; i++) {
|
||||
playlists += '<option>' + obj.data[i].uri + '</option>';
|
||||
}
|
||||
document.getElementById('addToPlaylistPlaylist').innerHTML += playlists;
|
||||
if (obj.totalEntities > obj.returnedEntities) {
|
||||
obj.offset += settings.max_elements_per_page;
|
||||
sendAPI({"cmd":"MPD_API_GET_PLAYLISTS","data": {"offset": obj.offset, "filter": "-"}}, getAllPlaylists);
|
||||
}
|
||||
}
|
||||
|
||||
function showAddToPlaylist(uri) {
|
||||
modalAddToPlaylist.show();
|
||||
document.getElementById('addToPlaylistUri').value = uri;
|
||||
document.getElementById('addToPlaylistPlaylist').innerHTML = '';
|
||||
sendAPI({"cmd":"MPD_API_GET_PLAYLISTS","data": {"offset": 0, "filter": "-"}}, getAllPlaylists);
|
||||
}
|
||||
|
||||
function addToPlaylist() {
|
||||
var uri = document.getElementById('addToPlaylistUri').value;
|
||||
var plistEl = document.getElementById('addToPlaylistPlaylist');
|
||||
var plist = plistEl.options[plistEl.selectedIndex].text;
|
||||
sendAPI({"cmd": "MPD_API_ADD_TO_PLAYLIST", "data": {"uri": uri, "plist": plist}});
|
||||
modalAddToPlaylist.hide();
|
||||
}
|
||||
|
||||
function showRenamePlaylist(from) {
|
||||
document.getElementById('renamePlaylistFrm').classList.remove('was-validated');
|
||||
document.getElementById('renamePlaylistTo').classList.remove('is-invalid');
|
||||
modalRenamePlaylist.show();
|
||||
document.getElementById('renamePlaylistFrom').value = from;
|
||||
document.getElementById('renamePlaylistTo').value = '';
|
||||
}
|
||||
|
||||
function renamePlaylist() {
|
||||
var from = document.getElementById('renamePlaylistFrom').value;
|
||||
var to = document.getElementById('renamePlaylistTo').value;
|
||||
var valid = to.replace(/\w/g,'');
|
||||
if (to != '' && to != from && valid == '') {
|
||||
sendAPI({"cmd": "MPD_API_PLAYLIST_RENAME", "data": {"from": from, "to": to}});
|
||||
modalRenamePlaylist.hide();
|
||||
sendAPI({"cmd":"MPD_API_GET_PLAYLISTS","data": {"offset": app.current.page, "filter": app.current.filter}}, parsePlaylists);
|
||||
}
|
||||
else {
|
||||
document.getElementById('renamePlaylistTo').classList.add('is-invalid');
|
||||
document.getElementById('renamePlaylistFrm').classList.add('was-validated');
|
||||
}
|
||||
}
|
||||
|
||||
function showMenu(el) {
|
||||
var type = el.getAttribute('data-type');
|
||||
var uri = decodeURI(el.getAttribute('data-uri'));
|
||||
@ -1201,22 +1328,32 @@ function showMenu(el) {
|
||||
uri + '\',' + nextsongpos + ',\'' + name + '\']}">Add after current playing song</a>' : '') +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'replaceQueue\', \'options\': [\'' + type + '\',\'' +
|
||||
uri + '\',\'' + name + '\']}">Replace queue</a>' +
|
||||
// ( type != 'plist' ? '<div class="dropdown-divider"></div><a class="dropdown-item" href="#">Add to playlist</a>' : '') +
|
||||
( type != 'plist' ? '<div class="dropdown-divider"></div><a class="dropdown-item" href="#" data-href="{\'cmd\': \'showAddToPlaylist\', \'options\': [\'' + uri + '\']}">Add to playlist</a>' : '') +
|
||||
( type != 'dir' ? '<div class="dropdown-divider"></div>' : '') +
|
||||
( type == 'song' ? '<a class="dropdown-item" data-href="{\'cmd\': \'songDetails\', \'options\': [\'' + uri + '\']}" href="#">Songdetails</a>' : '');
|
||||
// ( type == 'plist' ? '<a class="dropdown-item" href="#">Show playlist</a>' : '');
|
||||
( type == 'song' ? '<a class="dropdown-item" data-href="{\'cmd\': \'songDetails\', \'options\': [\'' + uri + '\']}" href="#">Songdetails</a>' : '') +
|
||||
( type == 'plist' ? '<a class="dropdown-item" href="#" data-href="{\'cmd\': \'playlistDetails\', \'options\': [\'' + uri + '\']}">Show playlist</a>' : '');
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists') {
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') {
|
||||
menu += '<a class="dropdown-item" href="#" data-href="{\'cmd\': \'appendQueue\', \'options\': [\'' + type + '\',\'' +
|
||||
uri + '\',\'' + name + '\']}">Append to queue</a>' +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'replaceQueue\', \'options\': [\'' + type + '\',\'' +
|
||||
uri + '\',\'' + name + '\']}">Replace queue</a>' +
|
||||
'<div class="dropdown-divider"></div>' +
|
||||
// '<a class="dropdown-item" href="#">Show playlist</a>' +
|
||||
// '<a class="dropdown-item" href="#">Rename playlist</a>' +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'playlistDetails\', \'options\': [\'' + uri + '\']}">Edit playlist</a>' +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'showRenamePlaylist\', \'options\': [\'' + uri + '\']}">Rename playlist</a>' +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'delPlaylist\', \'options\': [\'' +
|
||||
uri + '\',\'' + name + '\']}">Delete playlist</a>';
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'Detail') {
|
||||
menu += '<a class="dropdown-item" href="#" data-href="{\'cmd\': \'appendQueue\', \'options\': [\'' + type + '\',\'' +
|
||||
uri + '\',\'' + name + '\']}">Append to queue</a>' +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'replaceQueue\', \'options\': [\'' + type + '\',\'' +
|
||||
uri + '\',\'' + name + '\']}">Replace queue</a>' +
|
||||
( document.getElementById('BrowsePlaylistsDetailList').getAttribute('data-ro') == 'false' ?
|
||||
'<div class="dropdown-divider"></div>' +
|
||||
'<a class="dropdown-item" href="#" data-href="{\'cmd\': \'removeFromPlaylist\', \'options\': [\'' + document.getElementById('BrowsePlaylistsDetailList').getAttribute('data-uri') + '\', \'' +
|
||||
el.parentNode.parentNode.getAttribute('data-songpos') + '\']}">Remove</a>' : '');
|
||||
}
|
||||
else if (app.current.app == 'Queue') {
|
||||
menu += '<a class="dropdown-item" href="#" data-href="{\'cmd\': \'delQueueSong\', \'options\': [\'single\',' +
|
||||
el.parentNode.parentNode.getAttribute('data-trackid') + ']}">Remove</a>' +
|
||||
@ -1262,7 +1399,7 @@ function sendAPI(request, callback) {
|
||||
if (ajaxRequest.responseText != '') {
|
||||
var obj = JSON.parse(ajaxRequest.responseText);
|
||||
if (obj.type == 'error') {
|
||||
showNotification('Error', obj.data, obj.data, 'error');
|
||||
showNotification('Error', obj.data, obj.data, 'danger');
|
||||
console.log('Error: ' + obj.data);
|
||||
}
|
||||
else if (obj.type == 'result' && obj.data != 'ok')
|
||||
@ -1284,7 +1421,7 @@ function openLocalPlayer() {
|
||||
|
||||
function updateDB() {
|
||||
sendAPI({"cmd": "MPD_API_UPDATE_DB"});
|
||||
// showNotification('Updating MPD Database...', '', '', 'success');
|
||||
showNotification('Updating MPD Database...', '', '', 'success');
|
||||
}
|
||||
|
||||
function clickPlay() {
|
||||
@ -1439,7 +1576,7 @@ function showNotification(notificationTitle,notificationText,notificationHtml,no
|
||||
else {
|
||||
alertBox = document.getElementById('alertBox');
|
||||
}
|
||||
alertBox.classList.remove('alert-success', 'alert-error');
|
||||
alertBox.classList.remove('alert-success', 'alert-danger');
|
||||
alertBox.classList.add('alert','alert-' + notificationType);
|
||||
alertBox.innerHTML = '<div><strong>' + notificationTitle + '</strong><br/>' + notificationHtml + '</div>';
|
||||
document.getElementsByTagName('main')[0].append(alertBox);
|
||||
@ -1466,7 +1603,7 @@ function notificationsSupported() {
|
||||
}
|
||||
|
||||
function songChange(obj) {
|
||||
if (obj.type == 'error')
|
||||
if (obj.type == 'error' || obj.type == 'result')
|
||||
return;
|
||||
var cur_song = obj.data.title + obj.data.artist + obj.data.album + obj.data.uri + obj.data.currentsongid;
|
||||
if (last_song == cur_song)
|
||||
@ -1479,7 +1616,7 @@ function songChange(obj) {
|
||||
|
||||
if(typeof obj.data.artist != 'undefined' && obj.data.artist.length > 0 && obj.data.artist != '-') {
|
||||
textNotification += obj.data.artist;
|
||||
htmlNotification += '<br/>' + obj.data.artist;
|
||||
htmlNotification += obj.data.artist;
|
||||
pageTitle += obj.data.artist + ' - ';
|
||||
document.getElementById('artist').innerText = obj.data.artist;
|
||||
} else {
|
||||
|
109
src/mpd_client.c
109
src/mpd_client.c
@ -78,7 +78,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
|
||||
switch(cmd_id) {
|
||||
case MPD_API_UNKNOWN:
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown request: %.*s\"}", msg.len, msg.p );
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"error\", \"data\": \"Unknown request\"}");
|
||||
break;
|
||||
case MPD_API_SET_SETTINGS:
|
||||
json_scanf(msg.p, msg.len, "{ data: { notificationWeb: %d, notificationPage: %d} }", &state.a, &state.b);
|
||||
@ -140,7 +140,7 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
case MPD_API_UPDATE_DB:
|
||||
uint_rc = mpd_run_update(mpd.conn, NULL);
|
||||
if (uint_rc > 0)
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Updating MPD Database...\"}");
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
|
||||
break;
|
||||
case MPD_API_SET_PAUSE:
|
||||
mpd_run_toggle_pause(mpd.conn);
|
||||
@ -254,6 +254,15 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
free(p_charbuf2);
|
||||
}
|
||||
break;
|
||||
case MPD_API_PLAYLIST_RENAME:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { from:%Q, to:%Q } }", &p_charbuf1, &p_charbuf2);
|
||||
if (je == 2) {
|
||||
mpd_run_rename(mpd.conn, p_charbuf1, p_charbuf2);
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Renamed playlist %s to %s\"}", p_charbuf1, p_charbuf2);
|
||||
free(p_charbuf1);
|
||||
free(p_charbuf2);
|
||||
}
|
||||
break;
|
||||
case MPD_API_GET_PLAYLISTS:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q } }", &uint_buf1, &p_charbuf1);
|
||||
if (je == 2) {
|
||||
@ -261,6 +270,39 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg)
|
||||
free(p_charbuf1);
|
||||
}
|
||||
break;
|
||||
case MPD_API_GET_PLAYLIST_LIST:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { uri: %Q, offset:%u, filter:%Q } }", &p_charbuf1, &uint_buf1, &p_charbuf2);
|
||||
if (je == 3) {
|
||||
n = mympd_put_playlist_list(mpd.buf, p_charbuf1, uint_buf1, p_charbuf2);
|
||||
free(p_charbuf1);
|
||||
free(p_charbuf2);
|
||||
}
|
||||
break;
|
||||
case MPD_API_ADD_TO_PLAYLIST:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { plist:%Q, uri:%Q } }", &p_charbuf1, &p_charbuf2);
|
||||
if (je == 2) {
|
||||
mpd_run_playlist_add(mpd.conn, p_charbuf1, p_charbuf2);
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"Added %s to playlist %s\"}", p_charbuf2, p_charbuf1);
|
||||
free(p_charbuf1);
|
||||
free(p_charbuf2);
|
||||
}
|
||||
break;
|
||||
case MPD_API_PLAYLIST_CLEAR:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q } }", &p_charbuf1);
|
||||
if (je == 1) {
|
||||
mpd_run_playlist_clear(mpd.conn, p_charbuf1);
|
||||
free(p_charbuf1);
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
|
||||
}
|
||||
break;
|
||||
case MPD_API_RM_PLAYLIST_TRACK:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { uri:%Q, track:%u } }", &p_charbuf1, &uint_buf1);
|
||||
if (je == 2) {
|
||||
mpd_run_playlist_delete(mpd.conn, p_charbuf1, uint_buf1);
|
||||
free(p_charbuf1);
|
||||
n = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"result\", \"data\": \"ok\"}");
|
||||
}
|
||||
break;
|
||||
case MPD_API_GET_FILESYSTEM:
|
||||
je = json_scanf(msg.p, msg.len, "{ data: { offset:%u, filter:%Q, path:%Q } }", &uint_buf1, &p_charbuf1, &p_charbuf2);
|
||||
if (je == 3) {
|
||||
@ -737,8 +779,10 @@ int mympd_put_current_song(char *buffer) {
|
||||
char cover[500];
|
||||
|
||||
song = mpd_run_current_song(mpd.conn);
|
||||
if(song == NULL)
|
||||
return 0;
|
||||
if (song == NULL) {
|
||||
len = json_printf(&out,"{type: result, data: ok}");
|
||||
return len;
|
||||
}
|
||||
|
||||
mympd_get_cover(mpd_song_get_uri(song),cover,500);
|
||||
|
||||
@ -1101,6 +1145,57 @@ int mympd_put_playlists(char *buffer, unsigned int offset, char *filter) {
|
||||
return len;
|
||||
}
|
||||
|
||||
int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *filter) {
|
||||
struct mpd_entity *entity;
|
||||
unsigned int entity_count = 0;
|
||||
unsigned int entities_returned = 0;
|
||||
const char *entityName;
|
||||
int len;
|
||||
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
|
||||
|
||||
if (!mpd_send_list_playlist_meta(mpd.conn, uri))
|
||||
RETURN_ERROR_AND_RECOVER("mpd_send_list_meta");
|
||||
|
||||
len = json_printf(&out, "{ type: playlist_detail, data: [ ");
|
||||
|
||||
while((entity = mpd_recv_entity(mpd.conn)) != NULL) {
|
||||
const struct mpd_song *song;
|
||||
entity_count ++;
|
||||
if (entity_count > offset && entity_count <= offset+MAX_ELEMENTS_PER_PAGE) {
|
||||
song = mpd_entity_get_song(entity);
|
||||
entityName = mympd_get_tag(song, MPD_TAG_TITLE);
|
||||
if (strncmp(filter,"-",1) == 0 || strncasecmp(filter,entityName,1) == 0 ||
|
||||
( strncmp(filter,"0",1) == 0 && isalpha(*entityName) == 0 )
|
||||
) {
|
||||
if (entities_returned ++) len += json_printf(&out,",");
|
||||
len += json_printf(&out, "{type: song, uri: %Q, album: %Q, artist: %Q, duration: %d, title: %Q, name: %Q }",
|
||||
mpd_song_get_uri(song),
|
||||
mympd_get_tag(song, MPD_TAG_ALBUM),
|
||||
mympd_get_tag(song, MPD_TAG_ARTIST),
|
||||
mpd_song_get_duration(song),
|
||||
entityName,
|
||||
entityName
|
||||
);
|
||||
} else {
|
||||
entity_count --;
|
||||
}
|
||||
}
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
|
||||
len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d, filter: %Q, uri: %Q }",
|
||||
entity_count,
|
||||
offset,
|
||||
entities_returned,
|
||||
filter,
|
||||
uri
|
||||
);
|
||||
|
||||
if (len > MAX_SIZE)
|
||||
fprintf(stderr,"Buffer truncated\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *searchstr) {
|
||||
struct mpd_song *song;
|
||||
unsigned long entity_count = 0;
|
||||
@ -1150,7 +1245,8 @@ int mympd_search(char *buffer, char *mpdtagtype, unsigned int offset, char *sear
|
||||
);
|
||||
}
|
||||
|
||||
if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n");
|
||||
if (len > MAX_SIZE)
|
||||
fprintf(stderr,"Buffer truncated\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -1180,7 +1276,8 @@ int mympd_search_add(char *buffer,char *mpdtagtype, char *searchstr) {
|
||||
mpd_song_free(song);
|
||||
}
|
||||
|
||||
if (len > MAX_SIZE) fprintf(stderr,"Buffer truncated\n");
|
||||
if (len > MAX_SIZE)
|
||||
fprintf(stderr,"Buffer truncated\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,10 @@
|
||||
X(MPD_API_REPLACE_TRACK) \
|
||||
X(MPD_API_ADD_PLAYLIST) \
|
||||
X(MPD_API_REPLACE_PLAYLIST) \
|
||||
X(MPD_API_RM_PLAYLIST_TRACK) \
|
||||
X(MPD_API_PLAYLIST_CLEAR) \
|
||||
X(MPD_API_PLAYLIST_RENAME) \
|
||||
X(MPD_API_ADD_TO_PLAYLIST) \
|
||||
X(MPD_API_PLAY_TRACK) \
|
||||
X(MPD_API_SAVE_QUEUE) \
|
||||
X(MPD_API_RM_TRACK) \
|
||||
@ -75,6 +79,7 @@
|
||||
X(MPD_API_SEND_SHUFFLE) \
|
||||
X(MPD_API_GET_STATS) \
|
||||
X(MPD_API_GET_PLAYLISTS) \
|
||||
X(MPD_API_GET_PLAYLIST_LIST) \
|
||||
X(MPD_API_RM_PLAYLIST) \
|
||||
X(MPD_API_GET_ARTISTALBUMS) \
|
||||
X(MPD_API_GET_ARTISTALBUMTITLES) \
|
||||
@ -146,6 +151,7 @@ int mympd_put_settings(char *buffer);
|
||||
int mympd_put_db_tag(char *buffer, unsigned int offset, char *mpdtagtype, char *mpdsearchtagtype, char *searchstr, char *filter);
|
||||
int mympd_put_songs_in_album(char *buffer, char *albumartist, char *album);
|
||||
int mympd_put_playlists(char *buffer, unsigned int offset, char *filter);
|
||||
int mympd_put_playlist_list(char *buffer, char *uri, unsigned int offset, char *filter);
|
||||
int mympd_put_songdetails(char *buffer, char *uri);
|
||||
void mympd_disconnect();
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user