From 3e9ca13fa3714a757e6c1fd18955787c018389eb Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Thu, 11 Jan 2018 11:06:26 -0800 Subject: [PATCH] upnpsoap: Add forced alphasort capability Add the ability to force title modification for clients that do their own alphanumeric sorting. Adding a '!' to the beginning of the force_sort_criteria value will enable this behavior. It is implemented by prepending all titles with a zero-padded number, and possibly season and episode (or disc and track) numbers if they aren't already in the title. --- minidlna.c | 5 +++++ minidlna.conf | 3 +++ minidlna.conf.5 | 4 ++++ upnpglobalvars.h | 1 + upnpsoap.c | 39 +++++++++++++++++++++++++++++++++++---- 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/minidlna.c b/minidlna.c index 3073435..ef45294 100644 --- a/minidlna.c +++ b/minidlna.c @@ -740,6 +740,11 @@ init(int argc, char **argv) break; case FORCE_SORT_CRITERIA: force_sort_criteria = ary_options[i].value; + if (force_sort_criteria[0] == '!') + { + SETFLAG(FORCE_ALPHASORT_MASK); + force_sort_criteria++; + } break; case MAX_CONNECTIONS: runtime_vars.max_connections = atoi(ary_options[i].value); diff --git a/minidlna.conf b/minidlna.conf index 9936463..fe2925c 100644 --- a/minidlna.conf +++ b/minidlna.conf @@ -80,6 +80,9 @@ model_number=1 #root_container=. # always force SortCriteria to this value, regardless of the SortCriteria passed by the client +# note: you can prepend the sort criteria with "!" to alter the titles of the objects so that they +# will be alphanumerically sorted in the order you specify here, to work around clients that do their +# own alphanumeric sorting. #force_sort_criteria=+upnp:class,+upnp:originalTrackNumber,+dc:title # maximum number of simultaneous connections diff --git a/minidlna.conf.5 b/minidlna.conf.5 index 256e094..8b97c4c 100644 --- a/minidlna.conf.5 +++ b/minidlna.conf.5 @@ -161,6 +161,10 @@ The possible values are: .IP "\fBforce_sort_criteria\fP" Always force SortCriteria to this value, regardless of the SortCriteria passed by the client. .nf +You may prepend the sort criteria with "!" to alter the titles of the objects so that they +will be alphanumerically sorted in the order you specify here, to work around clients that do +their own alphanumeric sorting. +.nf Example force_sort_criteria=+upnp:class,+upnp:originalTrackNumber,+dc:title diff --git a/upnpglobalvars.h b/upnpglobalvars.h index 9ce2712..8f3b2da 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -196,6 +196,7 @@ extern uint32_t runtime_flags; #define SCANNING_MASK 0x0100 #define RESCAN_MASK 0x0200 #define SUBTITLES_MASK 0x0400 +#define FORCE_ALPHASORT_MASK 0x0800 #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) (runtime_flags & mask) diff --git a/upnpsoap.c b/upnpsoap.c index dd0a5bf..8219937 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -77,6 +77,8 @@ #else # define __SORT_LIMIT #endif +#define NON_ZERO(x) (x && atoi(x)) +#define IS_ZERO(x) (!x || !atoi(x)) /* Standard Errors: * @@ -691,6 +693,35 @@ parse_sort_criteria(char *sortCriteria, int *error) return order; } +static void +_alphasort_alt_title(char **title, char **alt_title, int requested, int returned, const char *disc, const char *track) +{ + char *old_title = *alt_title ?: NULL; + char buf[8]; + int pad; + int ret; + + snprintf(buf, sizeof(buf), "%d", requested); + pad = strlen(buf); + + if (NON_ZERO(track) && !strstr(*title, track)) { + if (NON_ZERO(disc)) + ret = asprintf(alt_title, "%0*d %s.%s %s", + pad, returned, disc, track, *title); + else + ret = asprintf(alt_title, "%0*d %s %s", + pad, returned, track, *title); + } + else + ret = asprintf(alt_title, "%0*d %s", pad, returned, *title); + + if (ret > 0) + *title = *alt_title; + else + *alt_title = NULL; + free(old_title); +} + inline static void add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, char *detailID, struct Response *args) @@ -796,9 +827,6 @@ object_exists(const char *object) " d.THUMBNAIL, d.CREATOR, d.DLNA_PN, d.MIME, d.ALBUM_ART, d.ROTATION, d.DISC " #define SELECT_COLUMNS "SELECT o.OBJECT_ID, o.PARENT_ID, o.REF_ID, " COLUMNS -#define NON_ZERO(x) (x && atoi(x)) -#define IS_ZERO(x) (!x || !atoi(x)) - static int callback(void *args, int argc, char **argv, char **azColName) { @@ -947,6 +975,9 @@ callback(void *args, int argc, char **argv, char **azColName) } else dlna_flags |= DLNA_FLAG_TM_I; + /* Force an alphabetical sort, for clients that like to do their own sorting */ + if( GETFLAG(FORCE_ALPHASORT_MASK) ) + _alphasort_alt_title(&title, &alt_title, passed_args->requested, passed_args->returned, disc, track); if( passed_args->flags & FLAG_SKIP_DLNA_PN ) dlna_pn = NULL; @@ -1022,7 +1053,7 @@ callback(void *args, int argc, char **argv, char **azColName) if( *mime == 'a' && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) { ret = strcatf(str, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track); } else if( *mime == 'v' ) { - if( passed_args->filter & FILTER_UPNP_EPISODESEASON ) + if( NON_ZERO(disc) && (passed_args->filter & FILTER_UPNP_EPISODESEASON) ) ret = strcatf(str, "<upnp:episodeSeason>%s</upnp:episodeSeason>", disc); if( passed_args->filter & FILTER_UPNP_EPISODENUMBER ) ret = strcatf(str, "<upnp:episodeNumber>%s</upnp:episodeNumber>", track);