mirror of
https://github.com/SuperBFG7/ympd
synced 2024-12-25 10:30:26 +00:00
Feat: jukebox mode - add whole album #57
Feat: jukebox mode - configurable number of tracks in queue #57
This commit is contained in:
parent
0ae38ae2ba
commit
fc115a9d1b
@ -743,16 +743,30 @@
|
||||
<hr/>
|
||||
<h4>Jukebox</h4>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6" data-toggle="buttons">
|
||||
<button data-href='{"cmd": "toggleBtn", "options": ["btnJukebox"]}' id="btnJukebox" type="button" class="btn btn-secondary btn-block" title="Jukebox">
|
||||
Jukebox
|
||||
</button>
|
||||
<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">Mode</div>
|
||||
</div>
|
||||
<select id="selectJukeboxMode" class="form-control custom-select border-secondary">
|
||||
<option value="0">Off</option>
|
||||
<option value="1">Track</option>
|
||||
<option value="2">Album</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group input-group col-md-6 border-secondary">
|
||||
<select id="jukeboxPlaylist" class="form-control custom-select border-secondary">
|
||||
<select id="selectJukeboxPlaylist" class="form-control custom-select border-secondary">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<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">Min. queue length</div>
|
||||
</div>
|
||||
<input id="inputJukeboxQueueLength" type="text" class="form-control border-secondary" value="1">
|
||||
<div class="invalid-feedback">Must be a number and > 0</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<h4>Notifications</h4>
|
||||
<div class="row">
|
||||
|
@ -808,7 +808,6 @@ function parseSettings(obj) {
|
||||
toggleBtn('btnConsume', obj.data.consume);
|
||||
toggleBtn('btnSingle', obj.data.single);
|
||||
toggleBtn('btnRepeat', obj.data.repeat);
|
||||
toggleBtn('btnJukebox', obj.data.jukeboxMode);
|
||||
|
||||
if (obj.data.crossfade != undefined) {
|
||||
document.getElementById('inputCrossfade').removeAttribute('disabled');
|
||||
@ -859,26 +858,26 @@ function parseSettings(obj) {
|
||||
var stickerEls = document.getElementsByClassName('stickers');
|
||||
var stickerElsLen = stickerEls.length;
|
||||
var displayStickers = obj.data.stickers == true ? '' : 'none';
|
||||
for (var i = 0; i < stickerElsLen; i++) {
|
||||
for (var i = 0; i < stickerElsLen; i++)
|
||||
stickerEls[i].style.display = displayStickers;
|
||||
}
|
||||
|
||||
var smartplsEls = document.getElementsByClassName('smartpls');
|
||||
var smartplsElsLen = smartplsEls.length;
|
||||
var displaySmartpls = obj.data.smartpls == true ? '' : 'none';
|
||||
for (var i = 0; i < smartplsElsLen; i++) {
|
||||
for (var i = 0; i < smartplsElsLen; i++)
|
||||
smartplsEls[i].style.display = displaySmartpls;
|
||||
}
|
||||
|
||||
if (obj.data.mixramp == true) {
|
||||
if (obj.data.mixramp == true)
|
||||
document.getElementsByClassName('mixramp')[0].style.display = '';
|
||||
} else {
|
||||
else
|
||||
document.getElementsByClassName('mixramp')[0].style.display = 'none';
|
||||
}
|
||||
|
||||
document.getElementById('selectJukeboxMode').value = obj.data.jukeboxMode;
|
||||
document.getElementById('inputJukeboxQueueLength').value = obj.data.jukeboxQueueLength;
|
||||
|
||||
settings = obj.data;
|
||||
|
||||
playlistEl = 'jukeboxPlaylist';
|
||||
playlistEl = 'selectJukeboxPlaylist';
|
||||
sendAPI({"cmd": "MPD_API_PLAYLIST_LIST", "data": {"offset": 0, "filter": "-"}}, getAllPlaylists);
|
||||
|
||||
settings.mpdstream = 'http://';
|
||||
@ -1544,12 +1543,12 @@ function getAllPlaylists(obj) {
|
||||
if (obj.offset == 0) {
|
||||
if (playlistEl == 'addToPlaylistPlaylist')
|
||||
playlists = '<option></option><option>New Playlist</option>';
|
||||
else if (playlistEl == 'jukeboxPlaylist')
|
||||
else if (playlistEl == 'selectJukeboxPlaylist')
|
||||
playlists = '<option>Database</option>';
|
||||
}
|
||||
for (var i = 0; i < nrItems; i++) {
|
||||
playlists += '<option';
|
||||
if (playlistEl == 'jukeboxPlaylist' && obj.data[i].uri == settings.jukeboxPlaylist)
|
||||
if (playlistEl == 'selectJukeboxPlaylist' && obj.data[i].uri == settings.jukeboxPlaylist)
|
||||
playlists += ' selected';
|
||||
playlists += '>' + obj.data[i].uri + '</option>';
|
||||
}
|
||||
@ -1831,7 +1830,8 @@ function showMenu(el, event) {
|
||||
addMenuItem({"cmd": "replaceQueue", "options": [type, uri, name]}, 'Replace queue') +
|
||||
(x.getAttribute('data-ro') == 'false' ? addMenuItem({"cmd": "removeFromPlaylist", "options": [x.getAttribute('data-uri'),
|
||||
el.parentNode.parentNode.getAttribute('data-songpos')]}, 'Remove') : '') +
|
||||
addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist');
|
||||
addMenuItem({"cmd": "showAddToPlaylist", "options": [uri]}, 'Add to playlist') +
|
||||
(uri.indexOf('http') == -1 ? addMenuItem({"cmd": "songDetails", "options": [uri]}, 'Songdetails') : '');
|
||||
}
|
||||
else if (app.current.app == 'Queue') {
|
||||
menu += addMenuItem({"cmd": "delQueueSong", "options": ["single", el.parentNode.parentNode.getAttribute('data-trackid')]}, 'Remove') +
|
||||
@ -1999,6 +1999,20 @@ function confirmSettings() {
|
||||
formOK = false;
|
||||
}
|
||||
}
|
||||
var inputJukeboxQueueLength = document.getElementById('inputJukeboxQueueLength');
|
||||
var value = parseInt(inputJukeboxQueueLength.value);
|
||||
if (!isNaN(value)) {
|
||||
if (value > 0) {
|
||||
inputJukeboxQueueLength.value = value;
|
||||
} else {
|
||||
inputJukeboxQueueLength.classList.add('is-invalid');
|
||||
formOK = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
inputJukeboxQueueLength.classList.add('is-invalid');
|
||||
formOK = false;
|
||||
}
|
||||
if (settings.mixramp) {
|
||||
var inputMixrampdb = document.getElementById('inputMixrampdb');
|
||||
if (!inputMixrampdb.getAttribute('disabled')) {
|
||||
@ -2026,7 +2040,8 @@ function confirmSettings() {
|
||||
|
||||
if (formOK == true) {
|
||||
var selectReplaygain = document.getElementById('selectReplaygain');
|
||||
var selectJukeboxPlaylist = document.getElementById('jukeboxPlaylist');
|
||||
var selectJukeboxPlaylist = document.getElementById('selectJukeboxPlaylist');
|
||||
var selectJukeboxMode = document.getElementById('selectJukeboxMode');
|
||||
sendAPI({"cmd": "MPD_API_SETTINGS_SET", "data": {
|
||||
"consume": (document.getElementById('btnConsume').classList.contains('active') ? 1 : 0),
|
||||
"random": (document.getElementById('btnRandom').classList.contains('active') ? 1 : 0),
|
||||
@ -2038,8 +2053,9 @@ function confirmSettings() {
|
||||
"mixrampdelay": (settings.mixramp == true ? document.getElementById('inputMixrampdelay').value : settings.mixrampdelay),
|
||||
"notificationWeb": (document.getElementById('btnnotifyWeb').classList.contains('active') ? true : false),
|
||||
"notificationPage": (document.getElementById('btnnotifyPage').classList.contains('active') ? true : false),
|
||||
"jukeboxMode": (document.getElementById('btnJukebox').classList.contains('active') ? true : false),
|
||||
"jukeboxPlaylist": selectJukeboxPlaylist.options[selectJukeboxPlaylist.selectedIndex].value
|
||||
"jukeboxMode": selectJukeboxMode.options[selectJukeboxMode.selectedIndex].value,
|
||||
"jukeboxPlaylist": selectJukeboxPlaylist.options[selectJukeboxPlaylist.selectedIndex].value,
|
||||
"jukeboxQueueLength": document.getElementById('inputJukeboxQueueLength').value
|
||||
}}, getSettings);
|
||||
modalSettings.hide();
|
||||
} else
|
||||
|
141
src/mpd_client.c
141
src/mpd_client.c
@ -112,23 +112,25 @@ void callback_mympd(struct mg_connection *nc, const struct mg_str msg) {
|
||||
n = mympd_put_state(mpd.buf, &mpd.song_id, &mpd.next_song_id, &mpd.last_song_id, &mpd.queue_version, &mpd.queue_length);
|
||||
break;
|
||||
case MPD_API_SETTINGS_SET:
|
||||
je = json_scanf(msg.p, msg.len, "{data: {notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}}",
|
||||
je = json_scanf(msg.p, msg.len, "{data: {notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d}}",
|
||||
&mympd_state.notificationWeb,
|
||||
&mympd_state.notificationPage,
|
||||
&mympd_state.jukeboxMode,
|
||||
&mympd_state.jukeboxPlaylist);
|
||||
if (je == 4) {
|
||||
&mympd_state.jukeboxPlaylist,
|
||||
&mympd_state.jukeboxQueueLength);
|
||||
if (je == 5) {
|
||||
char tmpfile[400];
|
||||
char statefile[400];
|
||||
snprintf(tmpfile, 400, "%s/tmp/mympd.state", config.varlibdir );
|
||||
snprintf(statefile, 400, "%s/mympd.state", config.varlibdir );
|
||||
json_fprintf(tmpfile, "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}",
|
||||
json_fprintf(tmpfile, "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d}",
|
||||
mympd_state.notificationWeb,
|
||||
mympd_state.notificationPage,
|
||||
mympd_state.jukeboxMode,
|
||||
mympd_state.jukeboxPlaylist);
|
||||
mympd_state.jukeboxPlaylist,
|
||||
mympd_state.jukeboxQueueLength);
|
||||
rename(tmpfile, statefile);
|
||||
if (mympd_state.jukeboxMode == true)
|
||||
if (mympd_state.jukeboxMode > 0)
|
||||
mympd_jukebox();
|
||||
}
|
||||
|
||||
@ -597,7 +599,7 @@ void mympd_parse_idle(struct mg_mgr *s, int idle_bitmask) {
|
||||
break;
|
||||
case MPD_IDLE_QUEUE:
|
||||
len = snprintf(mpd.buf, MAX_SIZE, "{\"type\": \"update_queue\"}");
|
||||
if (mympd_state.jukeboxMode == true)
|
||||
if (mympd_state.jukeboxMode > 0)
|
||||
mympd_jukebox();
|
||||
break;
|
||||
case MPD_IDLE_PLAYER:
|
||||
@ -783,8 +785,8 @@ void mympd_idle(struct mg_mgr *s, int timeout) {
|
||||
mpd.conn_state = MPD_CONNECTED;
|
||||
mympd_mpd_features();
|
||||
mympd_smartpls_update_all();
|
||||
if (mympd_state.jukeboxMode == true)
|
||||
mympd_jukebox();
|
||||
if (mympd_state.jukeboxMode > 0)
|
||||
mympd_jukebox();
|
||||
mpd_send_idle(mpd.conn);
|
||||
break;
|
||||
|
||||
@ -976,9 +978,11 @@ char* mympd_get_tag(struct mpd_song const *song, enum mpd_tag_type tag) {
|
||||
void mympd_jukebox() {
|
||||
struct mpd_status *status;
|
||||
status = mpd_run_status(mpd.conn);
|
||||
int queue_length, num_songs, rand_song, i;
|
||||
int queue_length, num_songs, rand_song, i, j, addSongs;
|
||||
struct mpd_entity *entity;
|
||||
const struct mpd_song *song;
|
||||
struct mpd_pair *pair;
|
||||
char *album;
|
||||
|
||||
if (!status) {
|
||||
printf("MPD mpd_run_status: %s\n", mpd_connection_get_error_message(mpd.conn));
|
||||
@ -987,66 +991,86 @@ void mympd_jukebox() {
|
||||
}
|
||||
queue_length = mpd_status_get_queue_length(status);
|
||||
mpd_status_free(status);
|
||||
if (queue_length > 0)
|
||||
if (queue_length > mympd_state.jukeboxQueueLength)
|
||||
return;
|
||||
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
|
||||
struct mpd_stats *stats = mpd_run_stats(mpd.conn);
|
||||
num_songs = mpd_stats_get_number_of_songs(stats);
|
||||
mpd_stats_free(stats);
|
||||
|
||||
if (mympd_state.jukeboxMode == 2) {
|
||||
//Add whole album
|
||||
mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM);
|
||||
mpd_search_commit(mpd.conn);
|
||||
num_songs = 0;
|
||||
while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM)) != NULL) {
|
||||
num_songs++;
|
||||
mpd_return_pair(mpd.conn, pair);
|
||||
}
|
||||
mpd_response_finish(mpd.conn);
|
||||
num_songs--;
|
||||
if (num_songs > 0) {
|
||||
rand_song = rand() % num_songs;
|
||||
mpd_send_list_all(mpd.conn, "/");
|
||||
mpd_search_db_tags(mpd.conn, MPD_TAG_ALBUM);
|
||||
mpd_search_commit(mpd.conn);
|
||||
i = 0;
|
||||
while ((pair = mpd_recv_pair_tag(mpd.conn, MPD_TAG_ALBUM )) != NULL) {
|
||||
if (i == rand_song) {
|
||||
album = strdup(pair->value);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
mpd_return_pair(mpd.conn, pair);
|
||||
}
|
||||
mpd_return_pair(mpd.conn, pair);
|
||||
mpd_response_finish(mpd.conn);
|
||||
printf("Jukebox enabled, adding random album %s: %d/%d\n", album, rand_song, num_songs);
|
||||
mpd_send_command(mpd.conn, "searchadd", "Album", album, NULL);
|
||||
mpd_response_finish(mpd.conn);
|
||||
}
|
||||
}
|
||||
else if (mympd_state.jukeboxMode == 1) {
|
||||
//Add tracks
|
||||
if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0) {
|
||||
struct mpd_stats *stats = mpd_run_stats(mpd.conn);
|
||||
num_songs = mpd_stats_get_number_of_songs(stats);
|
||||
mpd_stats_free(stats);
|
||||
}
|
||||
else {
|
||||
mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist);
|
||||
num_songs = 0;
|
||||
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
|
||||
if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
|
||||
if (i == rand_song)
|
||||
break;
|
||||
i++;
|
||||
num_songs++;
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
}
|
||||
num_songs--;
|
||||
addSongs = mympd_state.jukeboxQueueLength - queue_length;
|
||||
if (num_songs > 0) {
|
||||
for (j = 0; j < addSongs; j++) {
|
||||
rand_song = rand() % num_songs;
|
||||
if (strcmp(mympd_state.jukeboxPlaylist, "Database") == 0)
|
||||
mpd_send_list_all(mpd.conn, "/");
|
||||
else
|
||||
mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist);
|
||||
i = 0;
|
||||
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
|
||||
if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
|
||||
if (i == rand_song)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
mpd_response_finish(mpd.conn);
|
||||
song = mpd_entity_get_song(entity);
|
||||
if (song != NULL) {
|
||||
printf("Jukebox enabled, adding random song: %d/%d\n", rand_song, num_songs);
|
||||
mpd_run_add(mpd.conn, mpd_song_get_uri(song));
|
||||
}
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
mpd_response_finish(mpd.conn);
|
||||
song = mpd_entity_get_song(entity);
|
||||
if (song != NULL) {
|
||||
printf("Jukebox enabled, playing random song from database: %d/%d\n", rand_song, num_songs);
|
||||
mpd_run_add(mpd.conn, mpd_song_get_uri(song));
|
||||
mpd_run_play(mpd.conn);
|
||||
}
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist);
|
||||
num_songs = 0;
|
||||
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
|
||||
num_songs++;
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
num_songs--;
|
||||
if (num_songs > 0) {
|
||||
rand_song = rand() % num_songs;
|
||||
mpd_send_list_playlist(mpd.conn, mympd_state.jukeboxPlaylist);
|
||||
i = 0;
|
||||
while ((entity = mpd_recv_entity(mpd.conn)) != NULL) {
|
||||
if (i == rand_song)
|
||||
break;
|
||||
i++;
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
mpd_response_finish(mpd.conn);
|
||||
song = mpd_entity_get_song(entity);
|
||||
if (song != NULL) {
|
||||
printf("Jukebox enabled, playing random song from %s: %d/%d\n", mympd_state.jukeboxPlaylist, rand_song, num_songs);
|
||||
mpd_run_add(mpd.conn, mpd_song_get_uri(song));
|
||||
mpd_run_play(mpd.conn);
|
||||
}
|
||||
mpd_entity_free(entity);
|
||||
}
|
||||
}
|
||||
mpd_run_play(mpd.conn);
|
||||
}
|
||||
|
||||
int mympd_put_state(char *buffer, int *current_song_id, int *next_song_id, int *last_song_id, unsigned *queue_version, unsigned *queue_length) {
|
||||
@ -1138,7 +1162,7 @@ int mympd_put_settings(char *buffer) {
|
||||
"repeat: %d, single: %d, crossfade: %d, consume: %d, random: %d, "
|
||||
"mixrampdb: %f, mixrampdelay: %f, mpdhost: %Q, mpdport: %d, passwort_set: %B, "
|
||||
"streamport: %d, coverimage: %Q, stickers: %B, mixramp: %B, smartpls: %B, maxElementsPerPage: %d, "
|
||||
"replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q, "
|
||||
"replaygain: %Q, notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d, "
|
||||
"tags: { Artist: %B, Album: %B, AlbumArtist: %B, Title: %B, Track: %B, Genre: %B, Date: %B,"
|
||||
"Composer: %B, Performer: %B }"
|
||||
"}}",
|
||||
@ -1163,6 +1187,7 @@ int mympd_put_settings(char *buffer) {
|
||||
mympd_state.notificationPage,
|
||||
mympd_state.jukeboxMode,
|
||||
mympd_state.jukeboxPlaylist,
|
||||
mympd_state.jukeboxQueueLength,
|
||||
mpd.tag_artist,
|
||||
mpd.tag_album,
|
||||
mpd.tag_album_artist,
|
||||
|
@ -178,8 +178,9 @@ typedef struct {
|
||||
typedef struct {
|
||||
bool notificationWeb;
|
||||
bool notificationPage;
|
||||
bool jukeboxMode;
|
||||
int jukeboxMode;
|
||||
const char* jukeboxPlaylist;
|
||||
int jukeboxQueueLength;
|
||||
} t_mympd_state;
|
||||
|
||||
t_mympd_state mympd_state;
|
||||
|
13
src/mympd.c
13
src/mympd.c
@ -244,22 +244,25 @@ int main(int argc, char **argv) {
|
||||
snprintf(statefile, 400, "%s/mympd.state", config.varlibdir);
|
||||
if (access(statefile, F_OK ) != -1 ) {
|
||||
char *content = json_fread(statefile);
|
||||
int je = json_scanf(content, strlen(content), "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %B, jukeboxPlaylist: %Q}",
|
||||
int je = json_scanf(content, strlen(content), "{notificationWeb: %B, notificationPage: %B, jukeboxMode: %d, jukeboxPlaylist: %Q, jukeboxQueueLength: %d}",
|
||||
&mympd_state.notificationWeb,
|
||||
&mympd_state.notificationPage,
|
||||
&mympd_state.jukeboxMode,
|
||||
&mympd_state.jukeboxPlaylist);
|
||||
if (je != 4) {
|
||||
&mympd_state.jukeboxPlaylist,
|
||||
&mympd_state.jukeboxQueueLength);
|
||||
if (je != 5) {
|
||||
mympd_state.notificationWeb = false;
|
||||
mympd_state.notificationPage = true;
|
||||
mympd_state.jukeboxMode = false;
|
||||
mympd_state.jukeboxMode = 0;
|
||||
mympd_state.jukeboxPlaylist = "Database";
|
||||
mympd_state.jukeboxQueueLength = 1;
|
||||
}
|
||||
} else {
|
||||
mympd_state.notificationWeb = false;
|
||||
mympd_state.notificationPage = true;
|
||||
mympd_state.jukeboxMode = false;
|
||||
mympd_state.jukeboxMode = 0;
|
||||
mympd_state.jukeboxPlaylist = "Database";
|
||||
mympd_state.jukeboxQueueLength = 1;
|
||||
}
|
||||
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
Loading…
Reference in New Issue
Block a user