mirror of
https://github.com/SuperBFG7/ympd
synced 2024-12-25 10:30:26 +00:00
Feat: last played songs card
This commit is contained in:
parent
7fdd0fe560
commit
ba187b17ce
@ -72,6 +72,7 @@ post_upgrade() {
|
||||
[ -f /var/lib/mympd/state/colsBrowsePlaylistsDetail ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsBrowsePlaylistsDetail
|
||||
[ -f /var/lib/mympd/state/colsQueue ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsQueue
|
||||
[ -f /var/lib/mympd/state/colsSearch ] || echo -n '["Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsSearch
|
||||
[ -f /var/lib/mympd/state/colsLastPlayed ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsLastPlayed
|
||||
|
||||
# fix ownership of /var/lib/mympd
|
||||
echo "INFO: Fixing ownership of /var/lib/mympd"
|
||||
|
@ -87,6 +87,7 @@ done
|
||||
[ -f /var/lib/mympd/state/colsBrowsePlaylistsDetail ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsBrowsePlaylistsDetail
|
||||
[ -f /var/lib/mympd/state/colsQueue ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsQueue
|
||||
[ -f /var/lib/mympd/state/colsSearch ] || echo -n '["Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsSearch
|
||||
[ -f /var/lib/mympd/state/colsLastPlayed ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsLastPlayed
|
||||
|
||||
echo "Fixing ownership of /var/lib/mympd"
|
||||
chown -R mympd.mympd /var/lib/mympd
|
||||
|
@ -54,3 +54,6 @@ syscmds = false
|
||||
|
||||
#Elements per page for pagination, max: 400
|
||||
max_elements_per_page = 100
|
||||
|
||||
#Number of songs keep in last played list
|
||||
last_played_count = 20
|
||||
|
1
debian/postinst
vendored
1
debian/postinst
vendored
@ -66,6 +66,7 @@ fi
|
||||
[ -f /var/lib/mympd/state/colsPlayback ] || echo -n '["Artist","Album","Genre"]' > /var/lib/mympd/state/colsPlayback
|
||||
[ -f /var/lib/mympd/state/colsBrowsePlaylistsDetail ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsBrowsePlaylistsDetail
|
||||
[ -f /var/lib/mympd/state/colsQueue ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsQueue
|
||||
[ -f /var/lib/mympd/state/colsLastPlayed ] || echo -n '["Pos","Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsLastPlayed
|
||||
[ -f /var/lib/mympd/state/colsSearch ] || echo -n '["Title","Artist","Album","Duration"]' > /var/lib/mympd/state/colsSearch
|
||||
|
||||
echo "Fixing ownership of /var/lib/mympd"
|
||||
|
@ -199,6 +199,62 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card hide" id="cardLastPlayed">
|
||||
<div class="card-header">Last Played Songs<span id="panel-heading-last-played" class="text pull-right"></span></div>
|
||||
<div class="card-body">
|
||||
<div class="btn-toolbar card-toolbar">
|
||||
<div id="LastPlayedPaginationTop" class="btn-group mr-2 hide">
|
||||
<button data-href='{"cmd": "gotoPage", "options": ["prev"]}' id="LastPlayedPaginationTopPrev" title="Previous Page" type="button" class="btn btn-secondary">«</button>
|
||||
<div class="input-group-append">
|
||||
<button id="LastPlayedPaginationTopPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
|
||||
<div class="dropdown-menu bg-dark px-2 pages" id="LastPlayedPaginationTopPages">
|
||||
</div>
|
||||
</div>
|
||||
<button data-href='{"cmd": "gotoPage", "options": ["next"]}' id="LastPlayedPaginationTopNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</button>
|
||||
</div>
|
||||
<div class="btn-group mr-2 featTags">
|
||||
<button id="LastPlayedColsBtn" class="btn btn-secondary dropdown-toggle material-icons" type="button" data-toggle="dropdown">settings</button>
|
||||
<div class="dropdown-menu bg-dark px-2" id="LastPlayedColsDropdown"><form></form>
|
||||
<button data-href='{"cmd": "saveCols", "options": ["LastPlayed"]}' class="btn btn-success btn-block btn-sm mt-2">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive-md">
|
||||
<table id="LastPlayedList" class="table table-hover table-sm">
|
||||
<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 hide" id="LastPlayedButtonsBottom">
|
||||
<div class="btn-group mr-2">
|
||||
<button type="button" class="btn btn-secondary material-icons" data-href='{"cmd": "scrollTo", "options: [0]}' title="To top">
|
||||
keyboard_arrow_up
|
||||
</button>
|
||||
</div>
|
||||
<div id="LastPlayedPaginationBottom" class="btn-group mr-2 dropup">
|
||||
<button data-href='{"cmd": "gotoPage", "options": ["prev"]}' id="LastPlayedPaginationBottomPrev" title="Previous Page" type="button" class="btn btn-secondary">«</button>
|
||||
<div class="input-group-append">
|
||||
<button id="LastPlayedPaginationBottomPage" class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">1 / 1</button>
|
||||
<div class="dropdown-menu bg-dark px-2 pages" id="LastPlayedPaginationBottomPages">
|
||||
</div>
|
||||
</div>
|
||||
<button data-href='{"cmd": "gotoPage", "options": ["next"]}' id="LastPlayedPaginationBottomNext" title="Next Page" type="button" class="btn btn-secondary input-group-append">»</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card hide" id="cardBrowse">
|
||||
<div class="card-header" id="panel-heading-browse">
|
||||
<ul class="nav nav-tabs card-header-tabs">
|
||||
|
@ -37,9 +37,10 @@ var dragEl;
|
||||
var playlistEl;
|
||||
|
||||
var app = {};
|
||||
app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Queue": { "state": "0/any/", "scrollPos": 0 },
|
||||
"Browse": {
|
||||
app.apps = { "Playback": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Queue": { "state": "0/any/", "scrollPos": 0 },
|
||||
"LastPlayed": { "state": "0/any/", "scrollPos": 0 },
|
||||
"Browse": {
|
||||
"active": "Database",
|
||||
"tabs": { "Filesystem": { "state": "0/-/", "scrollPos": 0 },
|
||||
"Playlists": {
|
||||
@ -96,7 +97,7 @@ var modalSaveSmartPlaylist = new Modal(document.getElementById('modalSaveSmartPl
|
||||
var modalDeletePlaylist = new Modal(document.getElementById('modalDeletePlaylist'));
|
||||
var modalHelp = new Modal(document.getElementById('modalHelp'));
|
||||
|
||||
var dropdownMainMenu;// = new Dropdown(document.getElementById('mainMenu'));
|
||||
var dropdownMainMenu;
|
||||
var dropdownVolumeMenu = new Dropdown(document.getElementById('volumeMenu'));
|
||||
|
||||
var collapseDBupdate = new Collapse(document.getElementById('navDBupdate'));
|
||||
@ -111,6 +112,7 @@ function appPrepare(scrollPos) {
|
||||
document.getElementById('cardQueue').classList.add('hide');
|
||||
document.getElementById('cardBrowse').classList.add('hide');
|
||||
document.getElementById('cardSearch').classList.add('hide');
|
||||
document.getElementById('cardLastPlayed').classList.add('hide');
|
||||
for (var i = 0; i < domCache.panelHeadingBrowseLen; i++) {
|
||||
domCache.panelHeadingBrowse[i].classList.remove('active');
|
||||
}
|
||||
@ -119,7 +121,8 @@ function appPrepare(scrollPos) {
|
||||
document.getElementById('cardBrowseFilesystem').classList.add('hide');
|
||||
//show active card + nav
|
||||
document.getElementById('card' + app.current.app).classList.remove('hide');
|
||||
document.getElementById('nav' + app.current.app).classList.add('active');
|
||||
if (document.getElementById('nav' + app.current.app))
|
||||
document.getElementById('nav' + app.current.app).classList.add('active');
|
||||
if (app.current.tab != undefined) {
|
||||
document.getElementById('card' + app.current.app + app.current.tab).classList.remove('hide');
|
||||
document.getElementById('card' + app.current.app + 'Nav' + app.current.tab).classList.add('active');
|
||||
@ -203,6 +206,9 @@ function appRoute() {
|
||||
selectTag('searchqueuetags', 'searchqueuetagsdesc', app.current.filter);
|
||||
getQueue();
|
||||
}
|
||||
else if (app.current.app == 'LastPlayed') {
|
||||
sendAPI({"cmd": "MPD_API_QUEUE_LAST_PLAYED", "data": {"offset": app.current.page}}, parseLastPlayed);
|
||||
}
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Playlists' && app.current.view == 'All') {
|
||||
sendAPI({"cmd": "MPD_API_PLAYLIST_LIST", "data": {"offset": app.current.page, "filter": app.current.filter}}, parsePlaylists);
|
||||
doSetFilterLetter('BrowsePlaylistsFilter');
|
||||
@ -264,10 +270,13 @@ function appRoute() {
|
||||
if (searchstrEl.value == '' && app.current.search != '')
|
||||
searchstrEl.value = app.current.search;
|
||||
if (app.last.app != app.current.app) {
|
||||
if (app.current.search != '')
|
||||
if (app.current.search != '') {
|
||||
var colspan = settings['cols' + app.current.app].length;
|
||||
colspan--;
|
||||
document.getElementById('SearchList').getElementsByTagName('tbody')[0].innerHTML=
|
||||
'<tr><td><span class="material-icons">search</span></td>' +
|
||||
'<td colspan="5">Searching...</td></tr>';
|
||||
'<td colspan="' + colspan + '">Searching...</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
if (app.current.search.length >= 2) {
|
||||
@ -455,10 +464,14 @@ function appInit() {
|
||||
document.getElementById('QueueList').addEventListener('click', function(event) {
|
||||
if (event.target.nodeName == 'TD')
|
||||
sendAPI({"cmd": "MPD_API_PLAYER_PLAY_TRACK","data": {"track": event.target.parentNode.getAttribute('data-trackid')}});
|
||||
else if (event.target.nodeName == 'A') {
|
||||
else if (event.target.nodeName == 'A')
|
||||
showMenu(event.target, event);
|
||||
}
|
||||
}, false);
|
||||
|
||||
document.getElementById('LastPlayedList').addEventListener('click', function(event) {
|
||||
if (event.target.nodeName == 'A')
|
||||
showMenu(event.target, event);
|
||||
}, false);
|
||||
|
||||
document.getElementById('BrowseFilesystemList').addEventListener('click', function(event) {
|
||||
if (event.target.nodeName == 'TD') {
|
||||
@ -566,7 +579,7 @@ function appInit() {
|
||||
}, false);
|
||||
|
||||
var dropdowns = ['QueueColsDropdown', 'BrowseFilesystemColsDropdown', 'SearchColsDropdown', 'BrowsePlaylistsDetailColsDropdown',
|
||||
'BrowseDatabaseColsDropdown', 'PlaybackColsDropdown'];
|
||||
'BrowseDatabaseColsDropdown', 'PlaybackColsDropdown', 'LastPlayedColsDropdown'];
|
||||
for (var i = 0; i < dropdowns.length; i++) {
|
||||
document.getElementById(dropdowns[i]).addEventListener('click', function(event) {
|
||||
if (event.target.nodeName == 'INPUT')
|
||||
@ -601,6 +614,7 @@ function appInit() {
|
||||
dragAndDropTable('QueueList');
|
||||
dragAndDropTable('BrowsePlaylistsDetailList');
|
||||
dragAndDropTableHeader('Queue');
|
||||
dragAndDropTableHeader('LastPlayed');
|
||||
dragAndDropTableHeader('Search');
|
||||
dragAndDropTableHeader('BrowseFilesystem');
|
||||
dragAndDropTableHeader('BrowsePlaylistsDetail');
|
||||
@ -964,7 +978,7 @@ function filterCols(x) {
|
||||
if (settings.featTags == false)
|
||||
tags.push('Title');
|
||||
tags.push('Duration');
|
||||
if (x == 'colsQueue' || x == 'colsBrowsePlaylistsDetail')
|
||||
if (x == 'colsQueue' || x == 'colsBrowsePlaylistsDetail' || x == 'colsLastPlayed')
|
||||
tags.push('Pos');
|
||||
else if (x == 'colsBrowseFilesystem')
|
||||
tags.push('Type');
|
||||
@ -1046,6 +1060,7 @@ function parseSettings(obj) {
|
||||
app.apps.Search.state = '0/filename/';
|
||||
app.apps.Queue.state = '0/filename/';
|
||||
settings.colsQueue = ["Pos", "Title", "Duration"];
|
||||
settings.colsLastPlayed = ["Pos", "Title", "Duration"];
|
||||
settings.colsSearch = ["Title", "Duration"];
|
||||
settings.colsBrowseFilesystem = ["Type", "Title", "Duration"];
|
||||
settings.colsBrowseDatabase = ["Track", "Title", "Duration"];
|
||||
@ -1100,6 +1115,7 @@ function parseSettings(obj) {
|
||||
settings.browsetags.sort();
|
||||
filterCols('colsSearch');
|
||||
filterCols('colsQueue');
|
||||
filterCols('colsLastPlayed');
|
||||
filterCols('colsBrowsePlaylistsDetail');
|
||||
filterCols('colsBrowseFilesystem');
|
||||
filterCols('colsBrowseDatabase');
|
||||
@ -1144,12 +1160,15 @@ function parseSettings(obj) {
|
||||
|
||||
setCols('Queue');
|
||||
setCols('Search');
|
||||
setCols('LastPlayed');
|
||||
setCols('BrowseFilesystem');
|
||||
setCols('BrowsePlaylistsDetail');
|
||||
setCols('BrowseDatabase', '.tblAlbumTitles');
|
||||
setCols('Playback');
|
||||
if (app.current.app == 'Queue')
|
||||
getQueue();
|
||||
else if (app.current.app == 'LastPlayed')
|
||||
appRoute();
|
||||
else if (app.current.app == 'Search')
|
||||
appRoute();
|
||||
else if (app.current.app == 'Browse' && app.current.tab == 'Filesystem')
|
||||
@ -1166,7 +1185,7 @@ function setCols(table, className) {
|
||||
if (settings.featTags == false)
|
||||
tags.push('Title');
|
||||
tags.push('Duration');
|
||||
if (table == 'Queue' || table == 'BrowsePlaylistsDetail')
|
||||
if (table == 'Queue' || table == 'BrowsePlaylistsDetail' || table == 'LastPlayed')
|
||||
tags.push('Pos');
|
||||
if (table == 'BrowseFilesystem')
|
||||
tags.push('Type');
|
||||
@ -1399,6 +1418,9 @@ function parseState(obj) {
|
||||
for (var i = 0; i < pb.length; i++)
|
||||
pb[i].innerText = '';
|
||||
}
|
||||
|
||||
if (app.current.app == 'LastPlayed')
|
||||
sendAPI({"cmd": "MPD_API_QUEUE_LAST_PLAYED", "data": {"offset": app.current.page}}, parseLastPlayed);
|
||||
|
||||
lastState = obj;
|
||||
}
|
||||
@ -1475,17 +1497,65 @@ function parseQueue(obj) {
|
||||
tr[i].remove();
|
||||
}
|
||||
|
||||
var colspan = settings['cols' + app.current.app].length;
|
||||
colspan--;
|
||||
|
||||
if (obj.type == 'queuesearch' && nrItems == 0)
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="5">No results, please refine your search!</td></tr>';
|
||||
'<td colspan="' + colspan + '">No results, please refine your search!</td></tr>';
|
||||
else if (obj.type == 'queue' && nrItems == 0)
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="5">Empty queue</td></tr>';
|
||||
'<td colspan="' + colspan + '">Empty queue</td></tr>';
|
||||
|
||||
setPagination(obj.totalEntities);
|
||||
document.getElementById('QueueList').classList.remove('opacity05');
|
||||
}
|
||||
|
||||
function parseLastPlayed(obj) {
|
||||
if (app.current.app !== 'LastPlayed')
|
||||
return;
|
||||
|
||||
document.getElementById('panel-heading-last-played').innerText = obj.totalEntities + ' Songs';
|
||||
|
||||
var nrItems = obj.data.length;
|
||||
var table = document.getElementById(app.current.app + 'List');
|
||||
table.setAttribute('data-version', obj.queueVersion);
|
||||
var tbody = table.getElementsByTagName('tbody')[0];
|
||||
var tr = tbody.getElementsByTagName('tr');
|
||||
for (var i = 0; i < nrItems; i++) {
|
||||
var minutes = Math.floor(obj.data[i].Duration / 60);
|
||||
var seconds = obj.data[i].Duration - minutes * 60;
|
||||
obj.data[i].Duration = minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
|
||||
var row = document.createElement('tr');
|
||||
row.setAttribute('data-songpos', (obj.data[i].Pos + 1));
|
||||
row.setAttribute('data-uri', obj.data[i].uri);
|
||||
var tds = '';
|
||||
for (var c = 0; c < settings.colsLastPlayed.length; c++) {
|
||||
tds += '<td data-col="' + settings.colsLastPlayed[c] + '">' + obj.data[i][settings.colsLastPlayed[c]] + '</td>';
|
||||
}
|
||||
tds += '<td data-col="Action"><a href="#" class="material-icons color-darkgrey">playlist_add</a></td>';
|
||||
row.innerHTML = tds;
|
||||
if (i < tr.length)
|
||||
tr[i].replaceWith(row);
|
||||
else
|
||||
tbody.append(row);
|
||||
}
|
||||
var trLen = tr.length - 1;
|
||||
for (var i = trLen; i >= nrItems; i --) {
|
||||
tr[i].remove();
|
||||
}
|
||||
|
||||
var colspan = settings['cols' + app.current.app].length;
|
||||
colspan--;
|
||||
|
||||
if (nrItems == 0)
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="' + colspan + '">Empty list</td></tr>';
|
||||
|
||||
setPagination(obj.totalEntities);
|
||||
document.getElementById('LastPlayedList').classList.remove('opacity05');
|
||||
}
|
||||
|
||||
function parseSearch(obj) {
|
||||
if (app.current.app !== 'Search')
|
||||
return;
|
||||
@ -1574,7 +1644,7 @@ function parseFilesystem(obj) {
|
||||
|
||||
if (nrItems == 0)
|
||||
tbody.innerHTML = '<tr><td><span class="material-icons">error_outline</span></td>' +
|
||||
'<td colspan="5">No results</td></tr>';
|
||||
'<td colspan="' + colspan + '">No results</td></tr>';
|
||||
document.getElementById(app.current.app + (app.current.tab==undefined ? '' : app.current.tab) + 'List').classList.remove('opacity05');
|
||||
}
|
||||
|
||||
@ -1671,13 +1741,16 @@ function parsePlaylists(obj) {
|
||||
|
||||
setPagination(obj.totalEntities);
|
||||
|
||||
if (nrItems == 0)
|
||||
if (nrItems == 0) {
|
||||
var colspan = settings['cols' + list].length;
|
||||
colspan--;
|
||||
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>';
|
||||
'<td colspan="' + colspan + '">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>';
|
||||
'<td colspan="' + colspan + '">Empty playlist.</td></tr>';
|
||||
}
|
||||
|
||||
document.getElementById(app.current.app + app.current.tab + app.current.view + 'List').classList.remove('opacity05');
|
||||
}
|
||||
|
28
src/list.c
28
src/list.c
@ -140,6 +140,34 @@ int list_push(struct list *l, const char *data, int value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct node *list_node_extract(struct list *l, unsigned idx) {
|
||||
if (l->list == NULL) { return NULL; }
|
||||
struct node *current = l->list, **previous = &l->list;
|
||||
for (; idx > 0; idx--) {
|
||||
if (current->next == NULL)
|
||||
return NULL;
|
||||
previous = ¤t->next;
|
||||
current = current->next;
|
||||
}
|
||||
/* set the previous node's 'next' value to the current
|
||||
* nodes next value */
|
||||
*previous = current->next;
|
||||
/* null out this node's next value since it's not part of
|
||||
* a list anymore */
|
||||
current->next = NULL;
|
||||
l->length--;
|
||||
return current;
|
||||
}
|
||||
|
||||
int list_shift(struct list *l, unsigned idx) {
|
||||
struct node * extracted = list_node_extract(l, idx);
|
||||
if (extracted == NULL)
|
||||
return -1;
|
||||
free(extracted->data);
|
||||
free(extracted);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_free(struct list *l) {
|
||||
struct node *current = l->list, *tmp = NULL;
|
||||
while (current != NULL) {
|
||||
|
@ -13,6 +13,8 @@ struct list {
|
||||
|
||||
int list_init(struct list *l);
|
||||
int list_push(struct list *l, const char *data, int value);
|
||||
int list_shift(struct list *l, unsigned idx);
|
||||
struct node *list_node_extract(struct list *l, unsigned idx);
|
||||
int list_replace(struct list *l, int pos, const char *data, int value);
|
||||
int list_free(struct list *l);
|
||||
int list_get_value(const struct list *l, const char *data);
|
||||
|
100
src/mpd_client.c
100
src/mpd_client.c
@ -142,6 +142,10 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
|
||||
free(mympd_state.colsPlayback);
|
||||
mympd_state.colsPlayback = strdup(cols);
|
||||
}
|
||||
else if (strcmp(p_charbuf1,"colsLastPlayed")==0) {
|
||||
free(mympd_state.colsLastPlayed);
|
||||
mympd_state.colsLastPlayed = strdup(cols);
|
||||
}
|
||||
mympd_state_set(p_charbuf1, cols);
|
||||
free(p_charbuf1);
|
||||
}
|
||||
@ -396,6 +400,12 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
|
||||
n = mympd_put_queue(mpd.buf, uint_buf1, &mpd.queue_version, &mpd.queue_length);
|
||||
}
|
||||
break;
|
||||
case MPD_API_QUEUE_LAST_PLAYED:
|
||||
je = json_scanf(msg.p, msg.len, "{data: {offset: %u}}", &uint_buf1);
|
||||
if (je == 1) {
|
||||
n = mympd_put_last_played_songs(mpd.buf, uint_buf1);
|
||||
}
|
||||
break;
|
||||
case MPD_API_PLAYER_CURRENT_SONG:
|
||||
n = mympd_put_current_song(mpd.buf);
|
||||
break;
|
||||
@ -688,10 +698,14 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) {
|
||||
break;
|
||||
case MPD_IDLE_PLAYER:
|
||||
len = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length);
|
||||
if (config.stickers && mpd.song_id != mpd.last_song_id && mpd.last_update_sticker_song_id != mpd.song_id) {
|
||||
mympd_count_song_id(mpd.song_id, "playCount", 1);
|
||||
mympd_last_played_song_id(mpd.song_id);
|
||||
mpd.last_update_sticker_song_id = mpd.song_id;
|
||||
if (mpd.song_id != mpd.last_song_id) {
|
||||
if (mpd.last_last_played_id != mpd.song_id)
|
||||
mympd_last_played_list(mpd.song_id);
|
||||
if (config.stickers && mpd.last_update_sticker_song_id != mpd.song_id) {
|
||||
mympd_count_song_id(mpd.song_id, "playCount", 1);
|
||||
mympd_last_played_song_id(mpd.song_id);
|
||||
mpd.last_update_sticker_song_id = mpd.song_id;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MPD_IDLE_MIXER:
|
||||
@ -998,6 +1012,22 @@ void mympd_like_song_uri(const char *uri, int value) {
|
||||
LOG_ERROR_AND_RECOVER("mpd_send_sticker_set");
|
||||
}
|
||||
|
||||
void mympd_last_played_list(int song_id) {
|
||||
struct mpd_song *song;
|
||||
if (song_id > -1) {
|
||||
song = mpd_run_get_queue_song_id(mpd.conn, song_id);
|
||||
if (song) {
|
||||
list_push(&last_played, mpd_song_get_uri(song), 1);
|
||||
mpd.last_last_played_id = song_id;
|
||||
mpd_song_free(song);
|
||||
if (last_played.length > config.last_played_count) {
|
||||
list_shift(&last_played, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void mympd_last_played_song_id(int song_id) {
|
||||
struct mpd_song *song;
|
||||
if (song_id > -1) {
|
||||
@ -1441,13 +1471,16 @@ int mympd_put_settings(char *buffer) {
|
||||
}
|
||||
len += json_printf(&out, "]");
|
||||
}
|
||||
len += json_printf(&out, ", colsQueue: %s", mympd_state.colsQueue);
|
||||
len += json_printf(&out, ", colsSearch: %s", mympd_state.colsSearch);
|
||||
len += json_printf(&out, ", colsBrowseDatabase: %s", mympd_state.colsBrowseDatabase);
|
||||
len += json_printf(&out, ", colsBrowsePlaylistsDetail: %s", mympd_state.colsBrowsePlaylistsDetail);
|
||||
len += json_printf(&out, ", colsBrowseFilesystem: %s", mympd_state.colsBrowseFilesystem);
|
||||
len += json_printf(&out, ", colsPlayback: %s", mympd_state.colsPlayback);
|
||||
len += json_printf(&out, "}}");
|
||||
len += json_printf(&out, ", colsQueue: %s, colsSearch: %s, colsBrowseDatabase: %s, colsBrowsePlaylistsDetail: %s, "
|
||||
"colsBrowseFilesystem: %s, colsPlayback: %s, colsLastPlayed: %s}}",
|
||||
mympd_state.colsQueue,
|
||||
mympd_state.colsSearch,
|
||||
mympd_state.colsBrowseDatabase,
|
||||
mympd_state.colsBrowsePlaylistsDetail,
|
||||
mympd_state.colsBrowseFilesystem,
|
||||
mympd_state.colsPlayback,
|
||||
mympd_state.colsLastPlayed
|
||||
);
|
||||
|
||||
CHECK_RETURN_LEN();
|
||||
return len;
|
||||
@ -1616,6 +1649,51 @@ int mympd_put_songdetails(char *buffer, char *uri) {
|
||||
return len;
|
||||
}
|
||||
|
||||
int mympd_put_last_played_songs(char *buffer, unsigned int offset) {
|
||||
const struct mpd_song *song;
|
||||
struct mpd_entity *entity;
|
||||
int len;
|
||||
unsigned int entity_count = 0;
|
||||
unsigned int entities_returned = 0;
|
||||
struct json_out out = JSON_OUT_BUF(buffer, MAX_SIZE);
|
||||
|
||||
len = json_printf(&out, "{type: last_played_songs, data: [");
|
||||
|
||||
struct node *current = last_played.list;
|
||||
while (current != NULL) {
|
||||
entity_count++;
|
||||
if (entity_count > offset && entity_count <= offset + config.max_elements_per_page) {
|
||||
if (entities_returned++)
|
||||
len += json_printf(&out, ",");
|
||||
len += json_printf(&out, "{Pos: %d, ", entity_count);
|
||||
if (!mpd_send_list_all_meta(mpd.conn, current->data))
|
||||
RETURN_ERROR_AND_RECOVER("mpd_send_list_all_meta");
|
||||
if ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
|
||||
song = mpd_entity_get_song(entity);
|
||||
if (mpd.feat_tags == true)
|
||||
PUT_SONG_TAGS();
|
||||
else
|
||||
PUT_MIN_SONG_TAGS();
|
||||
mpd_entity_free(entity);
|
||||
mpd_response_finish(mpd.conn);
|
||||
}
|
||||
len += json_printf(&out, "}");
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
len += json_printf(&out, "], totalEntities: %d, offset: %d, returnedEntities: %d}",
|
||||
entity_count,
|
||||
offset,
|
||||
entities_returned
|
||||
);
|
||||
|
||||
CHECK_RETURN_LEN();
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mympd_put_queue(char *buffer, unsigned int offset, unsigned *queue_version, unsigned *queue_length) {
|
||||
struct mpd_entity *entity;
|
||||
unsigned long totalTime = 0;
|
||||
|
@ -86,6 +86,7 @@
|
||||
X(MPD_API_QUEUE_ADD_PLAYLIST) \
|
||||
X(MPD_API_QUEUE_REPLACE_PLAYLIST) \
|
||||
X(MPD_API_QUEUE_SHUFFLE) \
|
||||
X(MPD_API_QUEUE_LAST_PLAYED) \
|
||||
X(MPD_API_PLAYLIST_CLEAR) \
|
||||
X(MPD_API_PLAYLIST_RENAME) \
|
||||
X(MPD_API_PLAYLIST_MOVE_TRACK) \
|
||||
@ -157,6 +158,7 @@ struct t_mpd {
|
||||
unsigned queue_version;
|
||||
unsigned queue_length;
|
||||
int last_update_sticker_song_id;
|
||||
int last_last_played_id;
|
||||
|
||||
// Features
|
||||
const unsigned* protocol;
|
||||
@ -171,7 +173,7 @@ struct list mpd_tags;
|
||||
struct list mympd_tags;
|
||||
struct list mympd_searchtags;
|
||||
struct list mympd_browsetags;
|
||||
|
||||
struct list last_played;
|
||||
struct list syscmds;
|
||||
|
||||
typedef struct {
|
||||
@ -199,6 +201,7 @@ typedef struct {
|
||||
bool localplayer;
|
||||
long streamport;
|
||||
const char *streamurl;
|
||||
unsigned long last_played_count;
|
||||
} t_config;
|
||||
|
||||
t_config config;
|
||||
@ -222,6 +225,7 @@ typedef struct {
|
||||
char *colsBrowsePlaylistsDetail;
|
||||
char *colsBrowseFilesystem;
|
||||
char *colsPlayback;
|
||||
char *colsLastPlayed;
|
||||
} t_mympd_state;
|
||||
|
||||
t_mympd_state mympd_state;
|
||||
@ -241,6 +245,7 @@ void mympd_like_song_uri(const char *uri, int value);
|
||||
void mympd_last_played_song_uri(const char *uri);
|
||||
void mympd_last_played_song_id(int song_id);
|
||||
void mympd_get_sticker(const char *uri, t_sticker *sticker);
|
||||
void mympd_last_played_list(int song_id);
|
||||
void mympd_jukebox();
|
||||
bool mympd_state_get(char *name, char *value);
|
||||
bool mympd_state_set(const char *name, const char *value);
|
||||
@ -270,6 +275,7 @@ int mympd_put_songs_in_album(char *buffer, char *album, char *search, char *tag)
|
||||
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);
|
||||
int mympd_put_last_played_songs(char *buffer, unsigned int offset);
|
||||
int mympd_queue_crop(char *buffer);
|
||||
void mympd_disconnect();
|
||||
#endif
|
||||
|
12
src/mympd.c
12
src/mympd.c
@ -199,6 +199,8 @@ static int inihandler(void* user, const char* section, const char* name, const c
|
||||
p_config->localplayer = false;
|
||||
else if (MATCH("streamurl"))
|
||||
p_config->streamurl = strdup(value);
|
||||
else if (MATCH("last_played_count"))
|
||||
p_config->last_played_count = strtol(value, &crap, 10);
|
||||
else
|
||||
return 0; /* unknown section/name, error */
|
||||
|
||||
@ -318,6 +320,13 @@ void read_statefiles() {
|
||||
mympd_state.colsPlayback = strdup("[\"Artist\",\"Album\",\"Genre\"]");
|
||||
mympd_state_set("colsPlayback", mympd_state.colsPlayback);
|
||||
}
|
||||
|
||||
if (mympd_state_get("colsLastPlayed", value))
|
||||
mympd_state.colsLastPlayed = strdup(value);
|
||||
else {
|
||||
mympd_state.colsLastPlayed = strdup("[\"Pos\",\"Title\",\"Artist\",\"Album\",\"Duration\"]");
|
||||
mympd_state_set("colsLastPlayed", mympd_state.colsLastPlayed);
|
||||
}
|
||||
}
|
||||
|
||||
bool testdir(char *name, char *dirname) {
|
||||
@ -363,6 +372,7 @@ int main(int argc, char **argv) {
|
||||
config.browsetaglist = "Artist,Album,AlbumArtist,Genre,Composer,Performer";
|
||||
config.smartpls = true;
|
||||
config.max_elements_per_page = 100;
|
||||
config.last_played_count = 20;
|
||||
char *etcdir = strdup(argv[1]);
|
||||
config.etcdir = dirname(etcdir);
|
||||
config.syscmds = false;
|
||||
@ -371,6 +381,7 @@ int main(int argc, char **argv) {
|
||||
mpd.timeout = 3000;
|
||||
mpd.last_update_sticker_song_id = -1;
|
||||
mpd.last_song_id = -1;
|
||||
mpd.last_last_played_id = -1;
|
||||
mpd.feat_library = false;
|
||||
|
||||
if (argc == 2) {
|
||||
@ -487,6 +498,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
list_init(&mpd_tags);
|
||||
list_init(&mympd_tags);
|
||||
list_init(&last_played);
|
||||
|
||||
if (config.ssl == true)
|
||||
mg_set_protocol_http_websocket(nc_http);
|
||||
|
Loading…
Reference in New Issue
Block a user