Skip to content

Commit

Permalink
Feat: support playlistlength command #1213
Browse files Browse the repository at this point in the history
  • Loading branch information
jcorporation committed Feb 15, 2024
1 parent f429263 commit 94e0484
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 34 deletions.
83 changes: 70 additions & 13 deletions src/mpd_client/playlists.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "src/mpd_client/playlists.h"

#include "dist/rax/rax.h"
#include "src/lib/convert.h"
#include "src/lib/log.h"
#include "src/lib/random.h"
#include "src/lib/rax_extras.h"
Expand All @@ -29,6 +30,10 @@
static bool playlist_sort(struct t_partition_state *partition_state, const char *playlist, const char *tagstr, bool sortdesc, sds *error);
static bool replace_playlist(struct t_partition_state *partition_state, const char *new_pl,
const char *to_replace_pl, sds *error);
static bool mpd_worker_playlist_content_enumerate_mpd(struct t_partition_state *partition_state, const char *plist,
unsigned *count, unsigned *duration, sds *error);
static bool mpd_worker_playlist_content_enumerate_manual(struct t_partition_state *partition_state, const char *plist,
unsigned *count, unsigned *duration, sds *error);

/**
* Public functions
Expand Down Expand Up @@ -322,28 +327,80 @@ bool mpd_client_playlist_sort(struct t_partition_state *partition_state, const c
/**
* Counts the number of songs in the playlist
* @param partition_state pointer to partition specific states
* @param playlist playlist to enumerate
* @param empty_check true: checks only if playlist is not empty
* false: enumerates the complete playlist
* @param plist playlist to enumerate
* @param count pointer to unsigned for entity count
* @param duration pointer to unsigned for total playtime
* @param error pointer to an already allocated sds string for the error message
* @return number of songs or -1 on error
*/
int mpd_client_enum_playlist(struct t_partition_state *partition_state, const char *playlist, bool empty_check) {
int entity_count = 0;
if (mpd_send_list_playlist(partition_state->conn, playlist)) {
bool mpd_client_enum_playlist(struct t_partition_state *partition_state, const char *plist,
unsigned *count, unsigned *duration, sds *error)
{
return mpd_connection_cmp_server_version(partition_state->conn, 0, 24, 0) >= 0
? mpd_worker_playlist_content_enumerate_mpd(partition_state, plist, count, duration, error)
: mpd_worker_playlist_content_enumerate_manual(partition_state, plist, count, duration, error);
}

/**
* Enumerates the playlist and returns the count and total length
* This functions uses the playlistlength command of MPD 0.24
* @param partition_state pointer to partition state
* @param plist playlist name to enumerate
* @param count pointer to unsigned for entity count
* @param duration pointer to unsigned for total playtime
* @param error pointer to an already allocated sds string for the error message
* @return pointer to buffer
*/
static bool mpd_worker_playlist_content_enumerate_mpd(struct t_partition_state *partition_state, const char *plist,
unsigned *count, unsigned *duration, sds *error)
{
*count = 0;
*duration = 0;
if (mpd_send_playlistlength(partition_state->conn, plist)) {
struct mpd_pair *pair;
while ((pair = mpd_recv_pair(partition_state->conn)) != NULL) {
if (strcmp(pair->name, "songs") == 0) {
str2uint(count, pair->value);
}
else if (strcmp(pair->name, "playtime") == 0) {
str2uint(duration, pair->value);
}
mpd_return_pair(partition_state->conn, pair);
}
}
mpd_response_finish(partition_state->conn);
return mympd_check_error_and_recover(partition_state, error, "mpd_send_playlistlength");
}

/**
* Enumerates the playlist and returns the count and total length.
* This functions retrieves the complete playlist.
* @param partition_state pointer to partition state
* @param plist playlist name to enumerate
* @param count pointer to unsigned for entity count
* @param duration pointer to unsigned for total playtime
* @param error pointer to an already allocated sds string for the error message
* @return pointer to buffer
*/
static bool mpd_worker_playlist_content_enumerate_manual(struct t_partition_state *partition_state, const char *plist,
unsigned *count, unsigned *duration, sds *error)
{
unsigned entity_count = 0;
unsigned total_time = 0;
disable_all_mpd_tags(partition_state);
if (mpd_send_list_playlist_meta(partition_state->conn, plist)) {
struct mpd_song *song;
while ((song = mpd_recv_song(partition_state->conn)) != NULL) {
total_time += mpd_song_get_duration(song);
entity_count++;
mpd_song_free(song);
if (empty_check == true) {
break;
}
}
}
mpd_response_finish(partition_state->conn);
if (mympd_check_error_and_recover(partition_state, NULL, "mpd_send_list_playlist") == false) {
return -1;
}
return entity_count;
*count = entity_count;
*duration = total_time;
return mympd_check_error_and_recover(partition_state, error, "mpd_send_list_playlist_meta") &&
enable_mpd_tags(partition_state, &partition_state->mpd_state->tags_mympd);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/mpd_client/playlists.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ time_t mpd_client_get_playlist_mtime(struct t_partition_state *partition_state,
bool mpd_client_playlist_clear(struct t_partition_state *partition_state, const char *plist, sds *error);
bool mpd_client_playlist_shuffle(struct t_partition_state *partition_state, const char *uri, sds *error);
bool mpd_client_playlist_sort(struct t_partition_state *partition_state, const char *uri, const char *tagstr, bool sortdesc, sds *error);
int mpd_client_enum_playlist(struct t_partition_state *partition_state, const char *playlist, bool empty_check);
bool mpd_client_enum_playlist(struct t_partition_state *partition_state, const char *plist,
unsigned *count, unsigned *duration, sds *error);
int mpd_client_playlist_validate(struct t_partition_state *partition_state, const char *playlist, bool remove, sds *error);
int mpd_client_playlist_validate_all(struct t_partition_state *partition_state, bool remove, sds *error);
int64_t mpd_client_playlist_dedup(struct t_partition_state *partition_state, const char *playlist, bool remove, sds *error);
Expand Down
32 changes: 13 additions & 19 deletions src/mpd_worker/playlists.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include "src/mpd_worker/playlists.h"

#include "src/lib/jsonrpc.h"
#include "src/mpd_client/errorhandler.h"
#include "src/mpd_client/tags.h"
#include "src/lib/sds_extras.h"
#include "src/mpd_client/playlists.h"

/**
* Enumerates the playlist and returns the count and total length
Expand All @@ -21,25 +21,19 @@
*/
sds mpd_worker_playlist_content_enumerate(struct t_partition_state *partition_state, sds buffer, unsigned request_id, sds plist) {
enum mympd_cmd_ids cmd_id = MYMPD_API_PLAYLIST_CONTENT_ENUMERATE;
unsigned entity_count = 0;
unsigned total_time = 0;
disable_all_mpd_tags(partition_state);
if (mpd_send_list_playlist_meta(partition_state->conn, plist)) {
unsigned entities = 0;
unsigned playtime = 0;
sds error = sdsempty();
if (mpd_client_enum_playlist(partition_state, plist, &entities, &playtime, &error) == true) {
buffer = jsonrpc_respond_start(buffer, cmd_id, request_id);
struct mpd_song *song;
while ((song = mpd_recv_song(partition_state->conn)) != NULL) {
total_time += mpd_song_get_duration(song);
entity_count++;
mpd_song_free(song);
}
buffer = tojson_uint(buffer, "entities", entities, true);
buffer = tojson_uint(buffer, "playtime", playtime, true);
buffer = tojson_sds(buffer, "plist", plist, false);
buffer = jsonrpc_end(buffer);
}
mpd_response_finish(partition_state->conn);
if (mympd_check_error_and_recover_respond(partition_state, &buffer, cmd_id, request_id, "mpd_send_list_playlist_meta") == false) {
return buffer;
else {
jsonrpc_respond_message(buffer, cmd_id, request_id, JSONRPC_FACILITY_PLAYLIST, JSONRPC_SEVERITY_ERROR, error);
}
buffer = tojson_uint(buffer, "entities", entity_count, true);
buffer = tojson_uint(buffer, "playtime", total_time, true);
buffer = tojson_sds(buffer, "plist", plist, false);
buffer = jsonrpc_end(buffer);
FREE_SDS(error);
return buffer;
}
6 changes: 5 additions & 1 deletion src/mympd_api/playlists.c
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,11 @@ sds mympd_api_playlist_delete_all(struct t_partition_state *partition_state, sds
if (criteria == PLAYLIST_DELETE_EMPTY) {
struct t_list_node *current = playlists.head;
while (current != NULL) {
current->value_i = mpd_client_enum_playlist(partition_state, current->key, true);
unsigned count = 0;
unsigned duration = 0;
current->value_i = mpd_client_enum_playlist(partition_state, current->key, &count, &duration, NULL) == true
? count
: 1; // set it to not empty on error
current = current->next;
}
}
Expand Down

0 comments on commit 94e0484

Please sign in to comment.