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.
This commit is contained in:
Justin Maggard 2018-01-11 11:06:26 -08:00
parent c0e66e9997
commit 3e9ca13fa3
5 changed files with 48 additions and 4 deletions

View File

@ -740,6 +740,11 @@ init(int argc, char **argv)
break; break;
case FORCE_SORT_CRITERIA: case FORCE_SORT_CRITERIA:
force_sort_criteria = ary_options[i].value; force_sort_criteria = ary_options[i].value;
if (force_sort_criteria[0] == '!')
{
SETFLAG(FORCE_ALPHASORT_MASK);
force_sort_criteria++;
}
break; break;
case MAX_CONNECTIONS: case MAX_CONNECTIONS:
runtime_vars.max_connections = atoi(ary_options[i].value); runtime_vars.max_connections = atoi(ary_options[i].value);

View File

@ -80,6 +80,9 @@ model_number=1
#root_container=. #root_container=.
# always force SortCriteria to this value, regardless of the SortCriteria passed by the client # 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 #force_sort_criteria=+upnp:class,+upnp:originalTrackNumber,+dc:title
# maximum number of simultaneous connections # maximum number of simultaneous connections

View File

@ -161,6 +161,10 @@ The possible values are:
.IP "\fBforce_sort_criteria\fP" .IP "\fBforce_sort_criteria\fP"
Always force SortCriteria to this value, regardless of the SortCriteria passed by the client. Always force SortCriteria to this value, regardless of the SortCriteria passed by the client.
.nf .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 Example
force_sort_criteria=+upnp:class,+upnp:originalTrackNumber,+dc:title force_sort_criteria=+upnp:class,+upnp:originalTrackNumber,+dc:title

View File

@ -196,6 +196,7 @@ extern uint32_t runtime_flags;
#define SCANNING_MASK 0x0100 #define SCANNING_MASK 0x0100
#define RESCAN_MASK 0x0200 #define RESCAN_MASK 0x0200
#define SUBTITLES_MASK 0x0400 #define SUBTITLES_MASK 0x0400
#define FORCE_ALPHASORT_MASK 0x0800
#define SETFLAG(mask) runtime_flags |= mask #define SETFLAG(mask) runtime_flags |= mask
#define GETFLAG(mask) (runtime_flags & mask) #define GETFLAG(mask) (runtime_flags & mask)

View File

@ -77,6 +77,8 @@
#else #else
# define __SORT_LIMIT # define __SORT_LIMIT
#endif #endif
#define NON_ZERO(x) (x && atoi(x))
#define IS_ZERO(x) (!x || !atoi(x))
/* Standard Errors: /* Standard Errors:
* *
@ -691,6 +693,35 @@ parse_sort_criteria(char *sortCriteria, int *error)
return order; 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 inline static void
add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn,
char *detailID, struct Response *args) 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 " " 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 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 static int
callback(void *args, int argc, char **argv, char **azColName) callback(void *args, int argc, char **argv, char **azColName)
{ {
@ -947,6 +975,9 @@ callback(void *args, int argc, char **argv, char **azColName)
} }
else else
dlna_flags |= DLNA_FLAG_TM_I; 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 ) if( passed_args->flags & FLAG_SKIP_DLNA_PN )
dlna_pn = NULL; 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) ) { if( *mime == 'a' && (passed_args->filter & FILTER_UPNP_ORIGINALTRACKNUMBER) ) {
ret = strcatf(str, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track); ret = strcatf(str, "<upnp:originalTrackNumber>%s</upnp:originalTrackNumber>", track);
} else if( *mime == 'v' ) { } 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); ret = strcatf(str, "<upnp:episodeSeason>%s</upnp:episodeSeason>", disc);
if( passed_args->filter & FILTER_UPNP_EPISODENUMBER ) if( passed_args->filter & FILTER_UPNP_EPISODENUMBER )
ret = strcatf(str, "<upnp:episodeNumber>%s</upnp:episodeNumber>", track); ret = strcatf(str, "<upnp:episodeNumber>%s</upnp:episodeNumber>", track);