[patch] Minidlnaにてデフォルトの並び順を指定する / Specify the default sort order of Minidlna server

Minidlnaのファイルのソート順を変更するパッチを作ったのでメモ。

ソート機能がないUPnP clientを使ったとき、Minidlnaはファイルを名前順に一覧表示する。
これはこれで良いのだが、同じディレクトリ内にファイルがたくさんあるときなど、ファイルを日付順に並べたくなる場合もありますよね。あるんですよ。

ということで、clientがソート順を指定しない場合に、デフォルトの並び順をconfファイルで指定できるようにパッチを作ってみた。

CVS最新用 → Add-sort-order-option_1.1.0-cvs.patch
Version 1.0.25 (stable) 用 → Add-sort-order-option_1.0.25.patch

当てるときは、minidlnaのディレクトリ内にて-p1でお願いします。つまり
$ cd minidlna/
$ patch -p1 < /path/to/Add-sort-order-option_1.1.0-cvs.patch


CVS最新用はこんな感じ。タブはスペースに変換しています。
[PATCH] Add sort_order option for default sort order

While browsing files, some DLNA clients specify sort order, while
others don't. If the sort order is not specified then minidlna server
sorts files by name.
This patch lets the user to modify this default sorting behavior.
---
 minidlna.c       |   14 ++++++++++++++
 minidlna.conf    |    6 ++++++
 minidlna.conf.5  |   11 +++++++++++
 minidlnatypes.h  |    8 ++++++++
 options.c        |    3 ++-
 options.h        |    3 ++-
 upnpglobalvars.c |    1 +
 upnpglobalvars.h |    1 +
 upnpsoap.c       |   24 ++++++++++++++++++++++++
 9 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/minidlna.c b/minidlna.c
index d591a70..286250b 100644
--- a/minidlna.c
+++ b/minidlna.c
@@ -743,6 +743,20 @@ init(int argc, char **argv)
                                 uid = entry->pw_uid;
                         }
                         break;
+                case DEFAULT_SORT_ORDER:
+                        if (strcmp(ary_options[i].value, "nameasc") == 0) {
+                                default_sort_order = SORT_BY_NAME_ASC;
+                        } else if (strcmp(ary_options[i].value, "namedesc") == 0) {
+                                default_sort_order = SORT_BY_NAME_DESC;
+                        } else if (strcmp(ary_options[i].value, "dateasc") == 0) {
+                                default_sort_order = SORT_BY_DATE_ASC;
+                        } else if (strcmp(ary_options[i].value, "datedesc") == 0) {
+                                default_sort_order = SORT_BY_DATE_DESC;
+                        } else {
+                                DPRINTF(E_WARN, L_GENERAL, "unknown sort_order: %s\n", ary_options[i].value);
+                                default_sort_order = SORT_UNSPECIFIED;
+                        }
+                        break;
                 default:
                         DPRINTF(E_ERROR, L_GENERAL, "Unknown option in file %s\n",
                                 optionsfile);
diff --git a/minidlna.conf b/minidlna.conf
index bfb71d5..4cac261 100644
--- a/minidlna.conf
+++ b/minidlna.conf
@@ -69,3 +69,9 @@ model_number=1
 #   + "P" - "Pictures"
 # if you specify "B" and client device is audio-only then "Music/Folders" will be used as root
 #root_container=.
+
+# default sort order of the files
+# this value is used only if the client does not specify a sort order
+# possible values are: nameasc, namedesc, dateasc, or datedesc
+# (sort by file name ascending, file name descending, date ascending, date descending, respectively)
+#sort_order=nameasc
diff --git a/minidlna.conf.5 b/minidlna.conf.5
index 4b29a6c..c4124c1 100644
--- a/minidlna.conf.5
+++ b/minidlna.conf.5
@@ -158,6 +158,17 @@ The possible values are:
   "Music/Folders" will be used as root container and you wont see Videos.
 .fi
 
+.IP "\fBsort_order\fP"
+Default sort order of the files.
+This value is used only if the client does not specify a sort order.
+.nf
+The possible values are:
+             'nameasc'  meaning "sort by file name ascending" (this is the default)
+             'namedesc' meaning "sort by file name descending"
+             'dateasc'  meaning "sort by date ascending"
+             'datedesc' meaning "sort by date descending"
+.fi
+
 
 
 .SH VERSION
diff --git a/minidlnatypes.h b/minidlnatypes.h
index 4bc6833..673f65c 100644
--- a/minidlnatypes.h
+++ b/minidlnatypes.h
@@ -108,4 +108,12 @@ struct client_cache_s {
         time_t age;
 };
 
+enum sort_order_types {
+        SORT_UNSPECIFIED,
+        SORT_BY_NAME_ASC,
+        SORT_BY_NAME_DESC,
+        SORT_BY_DATE_ASC,
+        SORT_BY_DATE_DESC
+};
+
 #endif
diff --git a/options.c b/options.c
index 1ae6680..2cf48e8 100644
--- a/options.c
+++ b/options.c
@@ -62,7 +62,8 @@ static const struct {
         { ENABLE_TIVO, "enable_tivo" },
         { ENABLE_DLNA_STRICT, "strict_dlna" },
         { ROOT_CONTAINER, "root_container" },
-        { USER_ACCOUNT, "user" }
+        { USER_ACCOUNT, "user" },
+        { DEFAULT_SORT_ORDER, "sort_order" }
 };
 
 int
diff --git a/options.h b/options.h
index 609b5db..0396b16 100644
--- a/options.h
+++ b/options.h
@@ -55,7 +55,8 @@ enum upnpconfigoptions {
         ENABLE_TIVO,                   /* enable support for streaming images and music to TiVo */
         ENABLE_DLNA_STRICT,            /* strictly adhere to DLNA specs */
         ROOT_CONTAINER,                /* root ObjectID (instead of "0") */
-        USER_ACCOUNT                   /* user account to run as */
+        USER_ACCOUNT,                  /* user account to run as */
+        DEFAULT_SORT_ORDER             /* sort order if not specified by the client */
 };
 
 /* readoptionsfile()
diff --git a/upnpglobalvars.c b/upnpglobalvars.c
index 3d40700..d36c7de 100644
--- a/upnpglobalvars.c
+++ b/upnpglobalvars.c
@@ -93,3 +93,4 @@ struct client_cache_s clients[CLIENT_CACHE_SLOTS];
 short int scanning = 0;
 volatile short int quitting = 0;
 volatile uint32_t updateID = 0;
+enum sort_order_types default_sort_order = SORT_UNSPECIFIED;
diff --git a/upnpglobalvars.h b/upnpglobalvars.h
index e9d8e54..9770754 100644
--- a/upnpglobalvars.h
+++ b/upnpglobalvars.h
@@ -235,5 +235,6 @@ extern struct client_cache_s clients[CLIENT_CACHE_SLOTS];
 extern short int scanning;
 extern volatile short int quitting;
 extern volatile uint32_t updateID;
+extern enum sort_order_types default_sort_order;
 
 #endif
diff --git a/upnpsoap.c b/upnpsoap.c
index a6fb866..8701696 100644
--- a/upnpsoap.c
+++ b/upnpsoap.c
@@ -1221,6 +1221,30 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
                         goto browse_error;
                 }
 
+                if (orderBy == NULL) {
+                        int ret2 = 0;
+                        switch (default_sort_order) {
+                        case SORT_BY_NAME_ASC:
+                                ret2 = asprintf(&orderBy, "order by d.TITLE ASC");
+                                break;
+                        case SORT_BY_NAME_DESC:
+                                ret2 = asprintf(&orderBy, "order by d.TITLE DESC");
+                                break;
+                        case SORT_BY_DATE_ASC:
+                                /* TITLE ASC is added for "tiebreaker" - see parse_sort_criteria() */
+                                ret2 = asprintf(&orderBy, "order by d.DATE ASC, TITLE ASC");
+                                break;
+                        case SORT_BY_DATE_DESC:
+                                ret2 = asprintf(&orderBy, "order by d.DATE DESC, TITLE ASC");
+                                break;
+                        default:
+                                /* orderBy is left as it is */
+                                break;
+                        }
+                        if (ret2 < 0)
+                                orderBy = NULL;
+                }
+
                 sql = sqlite3_mprintf( SELECT_COLUMNS
                                       "from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
                                       " where PARENT_ID = '%q' %s limit %d, %d;",
-- 
1.7.9.5

ちなみに、今回のパッチとは直接関係ないけどMinidlnaの日時の扱いについてメモ。(調べたソースは2013/03/28時点でのCVS最新版)
  • 画像ファイル (jpg) の場合、Minidlnaは日時情報をExif情報から取得する。したがってExifが入っていないjpgファイルの場合、日時は空になる。
  • 音楽ファイルの場合、ファイル内に「年(year)」の情報があれば、その年の1月1日が日時情報になる。なければ日時は空になる。
  • ビデオファイルの場合は、単純にそのファイルの最終更新時刻を使っているっぽい。

ということで、日時による並び替えは場合によっては思ったとおりにならないかも。

コメントを投稿

0 コメント