Skip to content

Commit

Permalink
Feat: add MYMPD_API_QUEUE_MOVE_RELATIVE, readd MYMPD_API_QUEUE_MOVE_P…
Browse files Browse the repository at this point in the history
…OSITION #1001
  • Loading branch information
jcorporation committed May 22, 2023
1 parent 1103c34 commit fd78fdb
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 62 deletions.
12 changes: 8 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,31 @@ https://github.com/jcorporation/myMPD/

## myMPD v10.4.0 (not yet released)

This release improves the queue and playlist management in many ways.

### API changes

- MYMPD_API_QUEUE_RM_SONG -> MYMPD_API_QUEUE_RM_IDS
- MYMPD_API_QUEUE_MOVE_SONG -> MYMPD_API_QUEUE_MOVE_IDS
- MYMPD_API_QUEUE_MOVE_SONG -> MYMPD_API_QUEUE_MOVE_POSITION
- MYMPD_API_QUEUE_MOVE_RELATIVE: new
- MYMPD_API_QUEUE_APPEND_URI -> MYMPD_API_QUEUE_APPEND_URIS
- MYMPD_API_QUEUE_INSERT_URI -> MYMPD_API_QUEUE_INSERT_URIS
- MYMPD_API_QUEUE_REPLACE_URI -> MYMPD_API_QUEUE_REPLACE_URIS
- MYMPD_API_QUEUE_APPEND_PLAYLIST -> MYMPD_API_QUEUE_APPEND_PLAYLISTS
- MYMPD_API_QUEUE_INSERT_PLAYLIST -> MYMPD_API_QUEUE_INSERT_PLAYLISTS
- MYMPD_API_QUEUE_REPLACE_PLAYLIST -> MYMPD_API_QUEUE_REPLACE_PLAYLISTS
- MYMPD_API_QUEUE_PRIO_SET parameters changed
- MYMPD_API_QUEUE_PRIO_SET_HIGHEST parameters changed
- MYMPD_API_QUEUE_PRIO_SET: parameters changed
- MYMPD_API_QUEUE_PRIO_SET_HIGHEST: parameters changed
- MYMPD_API_PLAYLIST_CONTENT_RM_SONG -> MYMPD_API_PLAYLIST_CONTENT_RM_POSITIONS
- MYMPD_API_PLAYLIST_CONTENT_MOVE_SONG -> MYMPD_API_PLAYLIST_CONTENT_MOVE_POSITION
- MYMPD_API_PLAYLIST_CONTENT_APPEND_URI -> MYMPD_API_PLAYLIST_CONTENT_APPEND_URIS
- MYMPD_API_PLAYLIST_CONTENT_INSERT_URI -> MYMPD_API_PLAYLIST_CONTENT_INSERT_URIS
- MYMPD_API_PLAYLIST_CONTENT_REPLACE_URI -> MYMPD_API_PLAYLIST_CONTENT_REPLACE_URIS
- MYMPD_API_PLAYLIST_RM parameters changed
- MYMPD_API_PLAYLIST_RM: parameters changed

### Changelog

- Feat: Add multiple selections and actions #1001
- Feat: migrate to JavaScript fetch() API #1006
- Feat: add test target to cmake #1023
- Upd: Mongoose 7.10 #1024
Expand Down
20 changes: 11 additions & 9 deletions htdocs/js/QueueCurrent.js
Original file line number Diff line number Diff line change
Expand Up @@ -860,30 +860,32 @@ function gotoPlayingSong() {

/**
* Moves a entry in the queue
* @param {number} id song id
* @param {number} from from position
* @param {number} to to position
* @returns {void}
*/
function queueMoveId(id, to) {
sendAPI("MYMPD_API_QUEUE_MOVE_IDS", {
"songIds": [id],
function queueMoveSong(from, to) {
sendAPI("MYMPD_API_QUEUE_MOVE_POSITION", {
"from": from,
"to": to
}, null, false);
}

/**
* Plays the selected song after the current song.
* Uses the priority if MPS is in random mode, else moves the song after current playing song.
* Sets the priority if MPD is in random mode, else moves the song after current playing song.
* @param {number} songId current playing song id (for priority mode)
* @param {number} songPos current playing song position (for move mode)
* @returns {void}
*/
//eslint-disable-next-line no-unused-vars
function playAfterCurrent(songId, songPos) {
function playAfterCurrent(songId) {
if (settings.partition.random === false) {
//not in random mode - move song after current playing song
const newSongPos = currentState.songPos !== undefined ? currentState.songPos + 1 : 0;
queueMoveId(songId, newSongPos);
sendAPI("MYMPD_API_QUEUE_MOVE_RELATIVE", {
"songIds": [songId],
"to": 0,
"whence": 1
}, null, false);
}
else {
//in random mode - set song priority
Expand Down
14 changes: 11 additions & 3 deletions htdocs/js/apidoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,21 @@ const APImethods = {
}
}
},
"MYMPD_API_QUEUE_MOVE_IDS": {
"desc": "Moves song ids in the queue.",
"MYMPD_API_QUEUE_MOVE_POSITION": {
"desc": "Moves entries in the queue.",
"params": {
"songIds": APIparams.songIds,
"from": APIparams.from,
"to": APIparams.to
}
},
"MYMPD_API_QUEUE_MOVE_RELATIVE": {
"desc": "Moves entries in the queue.",
"params": {
"from": APIparams.songIds,
"to": APIparams.to,
"whence": APIparams.whence
}
},
"MYMPD_API_QUEUE_INSERT_PLAYLISTS": {
"desc": "Adds the playlist to distinct position in the queue.",
"params": {
Expand Down
5 changes: 3 additions & 2 deletions htdocs/js/contextMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -560,9 +560,10 @@ function createMenuLists(target, contextMenuTitle, contextMenuBody) {
addMenuItemsSongActions(dataNode, contextMenuBody, uri, type, name);
addDivider(contextMenuBody);
if (currentState.currentSongId !== -1 &&
songid !== currentState.currentSongId)
songid !== currentState.currentSongId &&
features.featWhence === true)
{
addMenuItem(contextMenuBody, {"cmd": "playAfterCurrent", "options": [songid, songpos]}, 'Play after current playing song');
addMenuItem(contextMenuBody, {"cmd": "playAfterCurrent", "options": [songid]}, 'Play after current playing song');
}
if (settings.partition.random === true) {
addMenuItem(contextMenuBody, {"cmd": "showSetSongPriority", "options": [songid]}, 'Set priority');
Expand Down
37 changes: 26 additions & 11 deletions htdocs/js/tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ function dragAndDropTable(tableId) {
}, false);
tableBody.addEventListener('dragleave', function(event) {
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TR') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TR')
{
return;
}
let target = event.target;
Expand All @@ -38,7 +40,9 @@ function dragAndDropTable(tableId) {
}, false);
tableBody.addEventListener('dragover', function(event) {
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TR') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TR')
{
return;
}
const tr = tableBody.querySelectorAll('.dragover');
Expand All @@ -56,7 +60,9 @@ function dragAndDropTable(tableId) {
}, false);
tableBody.addEventListener('dragend', function(event) {
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TR') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TR')
{
return;
}
const tr = tableBody.querySelectorAll('.dragover');
Expand All @@ -71,14 +77,17 @@ function dragAndDropTable(tableId) {
tableBody.addEventListener('drop', function(event) {
event.stopPropagation();
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TR') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TR')
{
return;
}
let target = event.target;
if (event.target.nodeName === 'TD') {
target = event.target.parentNode;
}
const newSongPos = getData(target, 'songpos');
const oldSongPos = getDataId(event.dataTransfer.getData('Text'), 'songpos');
document.getElementById(event.dataTransfer.getData('Text')).remove();
dragEl.classList.remove('opacity05');
// @ts-ignore
Expand All @@ -90,12 +99,10 @@ function dragAndDropTable(tableId) {
document.getElementById(tableId).classList.add('opacity05');
switch(app.id) {
case 'QueueCurrent': {
const songId = getDataId(event.dataTransfer.getData('Text'), 'songid');
queueMoveId(songId, newSongPos);
queueMoveSong(oldSongPos, newSongPos);
break;
}
case 'BrowsePlaylistsDetail': {
const oldSongPos = getDataId(event.dataTransfer.getData('Text'), 'songpos');
playlistMoveSong(oldSongPos, newSongPos);
break;
}
Expand Down Expand Up @@ -123,7 +130,9 @@ function dragAndDropTableHeader(tableName) {
}, false);
tableHeader.addEventListener('dragleave', function(event) {
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TH') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TH')
{
return;
}
if (event.target.nodeName === 'TH') {
Expand All @@ -132,7 +141,9 @@ function dragAndDropTableHeader(tableName) {
}, false);
tableHeader.addEventListener('dragover', function(event) {
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TH') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TH')
{
return;
}
const th = tableHeader.querySelectorAll('.dragover-th');
Expand All @@ -146,7 +157,9 @@ function dragAndDropTableHeader(tableName) {
}, false);
tableHeader.addEventListener('dragend', function(event) {
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TH') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TH')
{
return;
}
const th = tableHeader.querySelectorAll('.dragover-th');
Expand All @@ -161,7 +174,9 @@ function dragAndDropTableHeader(tableName) {
tableHeader.addEventListener('drop', function(event) {
event.stopPropagation();
event.preventDefault();
if (dragEl === undefined || dragEl.nodeName !== 'TH') {
if (dragEl === undefined ||
dragEl.nodeName !== 'TH')
{
return;
}
this.querySelector('[data-col=' + event.dataTransfer.getData('Text') + ']').remove();
Expand Down
3 changes: 2 additions & 1 deletion src/lib/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@
X(MYMPD_API_QUEUE_INSERT_SEARCH) \
X(MYMPD_API_QUEUE_INSERT_URIS) \
X(MYMPD_API_QUEUE_LIST) \
X(MYMPD_API_QUEUE_MOVE_IDS) \
X(MYMPD_API_QUEUE_MOVE_POSITION) \
X(MYMPD_API_QUEUE_MOVE_RELATIVE) \
X(MYMPD_API_QUEUE_PRIO_SET) \
X(MYMPD_API_QUEUE_PRIO_SET_HIGHEST) \
X(MYMPD_API_QUEUE_REPLACE_PLAYLISTS) \
Expand Down
31 changes: 25 additions & 6 deletions src/mympd_api/mympd_api_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,19 +898,37 @@ void mympd_api_handler(struct t_partition_state *partition_state, struct t_work_
response->data = mympd_respond_with_error_or_ok(partition_state, response->data, request->cmd_id, request->id, rc, "mpd_run_delete_range", &result);
}
break;
case MYMPD_API_QUEUE_MOVE_IDS: {
case MYMPD_API_QUEUE_MOVE_POSITION:
if (json_get_uint(request->data, "$.params.from", 0, MPD_PLAYLIST_LENGTH_MAX, &uint_buf1, &error) == true &&
json_get_uint(request->data, "$.params.to", 0, MPD_PLAYLIST_LENGTH_MAX, &uint_buf2, &error) == true)
{
if (uint_buf1 < uint_buf2) {
// decrease to position
uint_buf2--;
}
rc = mpd_run_move(partition_state->conn, uint_buf1, uint_buf2);
response->data = mympd_respond_with_error_or_ok(partition_state, response->data, request->cmd_id, request->id, rc, "mpd_run_move", &result);
}
break;
case MYMPD_API_QUEUE_MOVE_RELATIVE: {
if (mympd_state->mpd_state->feat_whence == false) {
response->data = jsonrpc_respond_message(response->data, request->cmd_id, request->id,
JSONRPC_FACILITY_QUEUE, JSONRPC_SEVERITY_ERROR, "Method not supported");
break;
}
struct t_list song_ids;
list_init(&song_ids);
if (json_get_array_llong(request->data, "$.params.songIds", &song_ids, MPD_COMMANDS_MAX, &error) == true &&
json_get_uint(request->data, "$.params.to", 0, MPD_PLAYLIST_LENGTH_MAX, &uint_buf1, &error) == true)
json_get_uint(request->data, "$.params.to", 0, MPD_PLAYLIST_LENGTH_MAX, &uint_buf1, &error) == true &&
json_get_uint(request->data, "$.params.whence", 0, 2, &uint_buf2, &error) == true)
{
if (song_ids.length == 0) {
response->data = jsonrpc_respond_message(response->data, request->cmd_id, request->id,
JSONRPC_FACILITY_QUEUE, JSONRPC_SEVERITY_ERROR, "No MPD queue song ids provided");
}
else {
rc = mympd_api_queue_move_ids(partition_state, &song_ids, uint_buf1);
response->data = mympd_respond_with_error_or_ok(partition_state, response->data, request->cmd_id, request->id, rc, "mpd_run_move", &result);
rc = mympd_api_queue_move_relative(partition_state, &song_ids, uint_buf1, uint_buf2);
response->data = mympd_respond_with_error_or_ok(partition_state, response->data, request->cmd_id, request->id, rc, "mympd_api_queue_move_relative", &result);
}
}
list_clear(&song_ids);
Expand All @@ -920,14 +938,14 @@ void mympd_api_handler(struct t_partition_state *partition_state, struct t_work_
struct t_list song_ids;
list_init(&song_ids);
if (json_get_array_llong(request->data, "$.params.songIds", &song_ids, MPD_COMMANDS_MAX, &error) == true &&
json_get_uint(request->data, "$.params.priority", 0, MPD_QUEUE_PRIO_MAX, &uint_buf2, &error) == true)
json_get_uint(request->data, "$.params.priority", 0, MPD_QUEUE_PRIO_MAX, &uint_buf1, &error) == true)
{
if (song_ids.length == 0) {
response->data = jsonrpc_respond_message(response->data, request->cmd_id, request->id,
JSONRPC_FACILITY_QUEUE, JSONRPC_SEVERITY_ERROR, "No MPD queue song ids provided");
}
else {
rc = mympd_api_queue_prio_set(partition_state, &song_ids, uint_buf2);
rc = mympd_api_queue_prio_set(partition_state, &song_ids, uint_buf1);
response->data = mympd_respond_with_error_or_ok(partition_state, response->data, request->cmd_id, request->id, rc, "mpd_send_prio_id", &result);
}
}
Expand Down Expand Up @@ -1223,6 +1241,7 @@ void mympd_api_handler(struct t_partition_state *partition_state, struct t_work_
json_get_uint(request->data, "$.params.to", 0, MPD_PLAYLIST_LENGTH_MAX, &uint_buf2, &error) == true)
{
if (uint_buf1 < uint_buf2) {
// decrease to position
uint_buf2--;
}
rc = mpd_run_playlist_move(partition_state->conn, sds_buf1, uint_buf1, uint_buf2);
Expand Down
51 changes: 26 additions & 25 deletions src/mympd_api/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,31 +151,6 @@ bool mympd_api_queue_play_newly_inserted(struct t_partition_state *partition_sta
return mympd_check_rc_error_and_recover(partition_state, rc, "mpd_run_play_id");
}

/**
* Moves the song ids to pos in queue.
* @param partition_state pointer to partition state
* @param song_ids song ids in the queue
* @param to position to move
* @return true on success, else false
*/
bool mympd_api_queue_move_ids(struct t_partition_state *partition_state, struct t_list *song_ids, unsigned to) {
if (mpd_command_list_begin(partition_state->conn, false) == true) {
struct t_list_node *current = song_ids->head;
while (current != NULL) {
bool rc = mpd_send_move_id(partition_state->conn, (unsigned)current->value_i, to);
if (rc == false) {
MYMPD_LOG_ERROR("Error adding command to command list mpd_send_move_id");
break;
}
current = current->next;
to++;
}
return mpd_command_list_end(partition_state->conn) &&
mpd_response_finish(partition_state->conn);
}
return false;
}

/**
* Sets the priority of a song in the queue.
* The priority has only an effect in random mode.
Expand Down Expand Up @@ -266,6 +241,32 @@ bool mympd_api_queue_append_plist(struct t_partition_state *partition_state, str
return false;
}

/**
* Moves song ids to relative position after current song
* @param partition_state pointer to partition state
* @param song_ids song ids to move
* @param to relative position
* @param whence how to interpret the to parameter
* @return bool true on success, else false
*/
bool mympd_api_queue_move_relative(struct t_partition_state *partition_state, struct t_list *song_ids, unsigned to, unsigned whence) {
if (mpd_command_list_begin(partition_state->conn, false) == true) {
struct t_list_node *current = song_ids->head;
while (current != NULL) {
bool rc = mpd_send_move_id_whence(partition_state->conn, (unsigned)current->value_i, to, whence);
if (rc == false) {
MYMPD_LOG_ERROR("Error adding command to command list mpd_send_move_id_whence");
break;
}
current = current->next;
to++;
}
return mpd_command_list_end(partition_state->conn) &&
mpd_response_finish(partition_state->conn);
}
return false;
}

/**
* Insert playlists into the queue
* @param partition_state pointer to partition state
Expand Down
2 changes: 1 addition & 1 deletion src/mympd_api/queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ bool mympd_api_queue_replace(struct t_partition_state *partition_state, struct t
bool mympd_api_queue_append_plist(struct t_partition_state *partition_state, struct t_list *plists);
bool mympd_api_queue_insert_plist(struct t_partition_state *partition_state, struct t_list *plists, unsigned to, unsigned whence);
bool mympd_api_queue_replace_plist(struct t_partition_state *partition_state, struct t_list *plists);
bool mympd_api_queue_move_ids(struct t_partition_state *partition_state, struct t_list *song_ids, unsigned to);
bool mympd_api_queue_move_relative(struct t_partition_state *partition_state, struct t_list *song_ids, unsigned to, unsigned whence);
#endif

0 comments on commit fd78fdb

Please sign in to comment.