summaryrefslogtreecommitdiff
path: root/libdleyna
diff options
context:
space:
mode:
authorMark Ryan <mark.d.ryan@intel.com>2013-06-17 14:05:14 +0200
committerLudovic Ferrandis <ludovic.ferrandis@intel.com>2013-06-24 11:11:22 +0200
commit2beeb7b4ba8b91a255de6213d980ef71824446f6 (patch)
tree609e6a8330b29933a684068ac1cb89b750d2c67d /libdleyna
parent961414d2e3e5545e6469427e46ace381748d22fe (diff)
downloaddleyna-server-2beeb7b4ba8b91a255de6213d980ef71824446f6.tar.gz
Added the new TypeEx property and fixed Type
The Type property is now almost consistent with the MediaServer2Spec Type property. This should remove a source of constant confusion and fix a number of bugs, in for example the download sync controller. dLeyna-server's implementation of Type differs only from MediaServer2Spec in one way. dLeyna-server has introduced one new value, item.unclassified, which is used when the object in question is an item but not one of the items supported by MediaServer2Spec, i.e., not an audio, video or image item. A new property, TypeEx has been introduced. TypeEx contains the extended type information for an object, i.e., the value Type used to hold (althought the values have changed), so if applications want the extended type they can still retrieve it. Both Type and TypeEx are searchable. The superset of values specified by TypeEx are permitted when creating a container, both in the type of the container and it its create classes. The extended type is exposed in the CreateClasses of a container and in the LastChange event. Type is no longer permitted in Update. TypeEx must be used. From an API point of view there are two breakagaes: 1. Applications that used Type to retrieve extended type information, need to be updated to use TypeEx. Applications that used Type in their search queries might also need to be updated. 2. Applications that updated the Type of an object will need to be updated to use TypeEx instead. There is one slightly unpleasent hack required to report the correct values for Search and Sort Caps. A correct solution would require making the p_map hash table many to many, which would result in a bigger change. I've left this improvement for another commit. Signed-off-by: Mark Ryan <mark.d.ryan@intel.com>
Diffstat (limited to 'libdleyna')
-rw-r--r--libdleyna/server/device.c36
-rw-r--r--libdleyna/server/interface.h1
-rw-r--r--libdleyna/server/props.c270
-rw-r--r--libdleyna/server/props.h5
-rw-r--r--libdleyna/server/search.c13
-rw-r--r--libdleyna/server/server.c2
6 files changed, 181 insertions, 146 deletions
diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c
index 1c3b6a4..36588b5 100644
--- a/libdleyna/server/device.c
+++ b/libdleyna/server/device.c
@@ -295,7 +295,7 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry,
if (!mclass)
goto on_error;
- media_class = dls_props_upnp_class_to_media_spec(mclass);
+ media_class = dls_props_upnp_class_to_media_spec_ex(mclass);
if (!media_class)
goto on_error;
@@ -769,9 +769,19 @@ static void prv_get_capabilities_analyze(GHashTable *property_map,
while (caps && *caps) {
prop_name = g_hash_table_lookup(property_map, *caps);
- if (prop_name)
+ if (prop_name) {
g_variant_builder_add(&caps_vb, "s", prop_name);
+ /* TODO: Okay this is not very nice. A better
+ way to fix this would be to change the p_map
+ to be many : many. */
+
+ if (!strcmp(*caps, "upnp:class"))
+ g_variant_builder_add(
+ &caps_vb, "s",
+ DLS_INTERFACE_PROP_TYPE_EX);
+ }
+
caps++;
}
@@ -2858,11 +2868,11 @@ static gchar *prv_create_new_container_didl(const gchar *parent_id,
GUPnPDIDLLiteContainer *container;
GVariantIter iter;
GVariant *child_type;
- const gchar *actual_type;
+ gchar *actual_type;
GUPnPOCMFlags flags;
gchar *retval = NULL;
- actual_type = dls_props_media_spec_to_upnp_class(
+ actual_type = dls_props_media_spec_ex_to_upnp_class(
task->ut.create_container.type);
if (!actual_type)
goto on_error;
@@ -2878,6 +2888,7 @@ static gchar *prv_create_new_container_didl(const gchar *parent_id,
task->ut.create_container.display_name);
gupnp_didl_lite_object_set_parent_id(item, parent_id);
gupnp_didl_lite_object_set_upnp_class(item, actual_type);
+ g_free(actual_type);
gupnp_didl_lite_object_set_restricted(item, FALSE);
flags = GUPNP_OCM_FLAGS_UPLOAD |
@@ -2890,11 +2901,13 @@ static gchar *prv_create_new_container_didl(const gchar *parent_id,
g_variant_iter_init(&iter, task->ut.create_container.child_types);
while ((child_type = g_variant_iter_next_value(&iter))) {
- actual_type = dls_props_media_spec_to_upnp_class(
+ actual_type = dls_props_media_spec_ex_to_upnp_class(
g_variant_get_string(child_type, NULL));
- if (actual_type != NULL)
+ if (actual_type != NULL) {
gupnp_didl_lite_container_add_create_class(container,
actual_type);
+ g_free(actual_type);
+ }
g_variant_unref(child_type);
}
@@ -3785,7 +3798,7 @@ static gchar *prv_get_current_xml_fragment(GUPnPDIDLLiteObject *object,
retval = gupnp_didl_lite_object_get_album_xml_string(object);
else if (mask & DLS_UPNP_MASK_PROP_DATE)
retval = gupnp_didl_lite_object_get_date_xml_string(object);
- else if (mask & DLS_UPNP_MASK_PROP_TYPE)
+ else if (mask & DLS_UPNP_MASK_PROP_TYPE_EX)
retval = gupnp_didl_lite_object_get_upnp_class_xml_string(
object);
else if (mask & DLS_UPNP_MASK_PROP_TRACK_NUMBER)
@@ -3803,7 +3816,7 @@ static gchar *prv_get_new_xml_fragment(GUPnPDIDLLiteObject *object,
{
GUPnPDIDLLiteContributor *artist;
const gchar *artist_name;
- const gchar *upnp_class;
+ gchar *upnp_class;
GVariantIter viter;
gchar *retval = NULL;
@@ -3825,13 +3838,14 @@ static gchar *prv_get_new_xml_fragment(GUPnPDIDLLiteObject *object,
g_variant_get_string(value, NULL));
retval = gupnp_didl_lite_object_get_date_xml_string(object);
- } else if (mask & DLS_UPNP_MASK_PROP_TYPE) {
- upnp_class = dls_props_media_spec_to_upnp_class(
- g_variant_get_string(value, NULL));
+ } else if (mask & DLS_UPNP_MASK_PROP_TYPE_EX) {
+ upnp_class = dls_props_media_spec_ex_to_upnp_class(
+ g_variant_get_string(value, NULL));
if (!upnp_class)
goto on_error;
gupnp_didl_lite_object_set_upnp_class(object, upnp_class);
+ g_free(upnp_class);
retval = gupnp_didl_lite_object_get_upnp_class_xml_string(
object);
diff --git a/libdleyna/server/interface.h b/libdleyna/server/interface.h
index 14a214b..be3b125 100644
--- a/libdleyna/server/interface.h
+++ b/libdleyna/server/interface.h
@@ -43,6 +43,7 @@ enum dls_interface_type_ {
#define DLS_INTERFACE_PROP_RESTRICTED "Restricted"
#define DLS_INTERFACE_PROP_DISPLAY_NAME "DisplayName"
#define DLS_INTERFACE_PROP_TYPE "Type"
+#define DLS_INTERFACE_PROP_TYPE_EX "TypeEx"
#define DLS_INTERFACE_PROP_CREATOR "Creator"
#define DLS_INTERFACE_PROP_DLNA_MANAGED "DLNAManaged"
#define DLS_INTERFACE_PROP_OBJECT_UPDATE_ID "ObjectUpdateID"
diff --git a/libdleyna/server/props.c b/libdleyna/server/props.c
index ad36174..cd6c30a 100644
--- a/libdleyna/server/props.c
+++ b/libdleyna/server/props.c
@@ -32,80 +32,46 @@
#include "path.h"
#include "props.h"
+static const gchar gUPnPObject[] = "object";
static const gchar gUPnPContainer[] = "object.container";
-static const gchar gUPnPAlbum[] = "object.container.album";
-static const gchar gUPnPPerson[] = "object.container.person";
-static const gchar gUPnPGenre[] = "object.container.genre";
-static const gchar gUPnPPlaylist[] = "object.container.playlistContainer";
-static const gchar gUPnPStorage[] = "object.container.storageFolder";
static const gchar gUPnPAudioItem[] = "object.item.audioItem";
static const gchar gUPnPVideoItem[] = "object.item.videoItem";
static const gchar gUPnPImageItem[] = "object.item.imageItem";
-static const gchar gUPnPPlaylistItem[] = "object.item.playlistItem";
static const gchar gUPnPItem[] = "object.item";
+static const unsigned int gUPnPObjectLen =
+ (sizeof(gUPnPObject) / sizeof(gchar)) - 1;
static const unsigned int gUPnPContainerLen =
(sizeof(gUPnPContainer) / sizeof(gchar)) - 1;
-static const unsigned int gUPnPAlbumLen =
- (sizeof(gUPnPAlbum) / sizeof(gchar)) - 1;
-static const unsigned int gUPnPPersonLen =
- (sizeof(gUPnPPerson) / sizeof(gchar)) - 1;
-static const unsigned int gUPnPGenreLen =
- (sizeof(gUPnPGenre) / sizeof(gchar)) - 1;
-static const unsigned int gUPnPPlaylistLen =
- (sizeof(gUPnPPlaylist) / sizeof(gchar)) - 1;
-static const unsigned int gUPnPStorageLen =
- (sizeof(gUPnPStorage) / sizeof(gchar)) - 1;
static const unsigned int gUPnPAudioItemLen =
(sizeof(gUPnPAudioItem) / sizeof(gchar)) - 1;
static const unsigned int gUPnPVideoItemLen =
(sizeof(gUPnPVideoItem) / sizeof(gchar)) - 1;
static const unsigned int gUPnPImageItemLen =
(sizeof(gUPnPImageItem) / sizeof(gchar)) - 1;
-static const unsigned int gUPnPPlaylistItemLen =
- (sizeof(gUPnPPlaylistItem) / sizeof(gchar)) - 1;
static const unsigned int gUPnPItemLen =
(sizeof(gUPnPItem) / sizeof(gchar)) - 1;
-static const gchar gUPnPPhotoAlbum[] = "object.container.album.photoAlbum";
-static const gchar gUPnPMusicAlbum[] = "object.container.album.musicAlbum";
-static const gchar gUPnPMusicArtist[] = "object.container.person.musicArtist";
-static const gchar gUPnPMovieGenre[] = "object.container.genre.movieGenre";
-static const gchar gUPnPMusicGenre[] = "object.container.genre.musicGenre";
static const gchar gUPnPMusicTrack[] = "object.item.audioItem.musicTrack";
-static const gchar gUPnPAudioBroadcast[] =
- "object.item.audioItem.audioBroadcast";
-static const gchar gUPnPAudioBook[] = "object.item.audioItem.audioBook";
static const gchar gUPnPMovie[] = "object.item.videoItem.movie";
-static const gchar gUPnPMusicVideoClip[] =
- "object.item.videoItem.musicVideoClip";
-static const gchar gUPnPVideoBroadcast[] =
- "object.item.videoItem.videoBroadcast";
static const gchar gUPnPPhoto[] = "object.item.imageItem.photo";
static const gchar gMediaSpec2Container[] = "container";
-static const gchar gMediaSpec2Album[] = "album";
-static const gchar gMediaSpec2AlbumPhoto[] = "album.photo";
-static const gchar gMediaSpec2AlbumMusic[] = "album.music";
-static const gchar gMediaSpec2Person[] = "person";
-static const gchar gMediaSpec2PersonMusicArtist[] = "person.musicartist";
-static const gchar gMediaSpec2Genre[] = "genre";
-static const gchar gMediaSpec2GenreMovie[] = "genre.movie";
-static const gchar gMediaSpec2GenreMusic[] = "genre.music";
-static const gchar gMediaSpec2AudioMusic[] = "audio.music";
-static const gchar gMediaSpec2AudioBroadcast[] = "audio.broadcast";
+static const gchar gMediaSpec2AudioMusic[] = "music";
static const gchar gMediaSpec2Audio[] = "audio";
-static const gchar gMediaSpec2AudioBook[] = "audio.book";
static const gchar gMediaSpec2Video[] = "video";
static const gchar gMediaSpec2VideoMovie[] = "video.movie";
-static const gchar gMediaSpec2VideoMusicClip[] = "video.musicclip";
-static const gchar gMediaSpec2VideoBroadcast[] = "video.broadcast";
static const gchar gMediaSpec2Image[] = "image";
static const gchar gMediaSpec2ImagePhoto[] = "image.photo";
-static const gchar gMediaSpec2Playlist[] = "playlist";
-static const gchar gMediaSpec2PlaylistItem[] = "item.playlist";
-static const gchar gMediaSpec2Item[] = "item";
-static const gchar gMediaSpec2Storage[] = "storage";
+static const gchar gMediaSpec2ItemUnclassified[] = "item.unclassified";
+
+static const gchar gMediaSpec2ExItem[] = "item";
+
+static const unsigned int gMediaSpec2ExItemLen =
+ (sizeof(gMediaSpec2ExItem) / sizeof(gchar)) - 1;
+
+static const unsigned int gMediaSpec2ContainerLen =
+ (sizeof(gMediaSpec2Container) / sizeof(gchar)) - 1;
typedef struct dls_prop_dlna_t_ dls_prop_dlna_t;
struct dls_prop_dlna_t_ {
@@ -396,10 +362,15 @@ void dls_prop_maps_new(GHashTable **property_map, GHashTable **filter_map)
/* upnp:class */
prop_t = prv_prop_map_new("upnp:class",
DLS_UPNP_MASK_PROP_TYPE,
- FALSE, TRUE, TRUE);
+ FALSE, TRUE, FALSE);
g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TYPE, prop_t);
g_hash_table_insert(p_map, "upnp:class", DLS_INTERFACE_PROP_TYPE);
+ prop_t = prv_prop_map_new("upnp:class",
+ DLS_UPNP_MASK_PROP_TYPE_EX,
+ FALSE, TRUE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TYPE_EX, prop_t);
+
/* upnp:containerUpdateID */
prop_t = prv_prop_map_new("upnp:containerUpdateID",
DLS_UPNP_MASK_PROP_CONTAINER_UPDATE_ID,
@@ -1147,7 +1118,7 @@ static GVariant *prv_compute_create_classes(GUPnPDIDLLiteContainer *container)
create_class = ptr->data;
content = gupnp_didl_lite_create_class_get_content(
create_class);
- ms2_class = dls_props_upnp_class_to_media_spec(content);
+ ms2_class = dls_props_upnp_class_to_media_spec_ex(content);
inc_derived = gupnp_didl_lite_create_class_get_include_derived(
create_class);
g_variant_builder_add(&create_classes_vb,
@@ -1160,66 +1131,75 @@ static GVariant *prv_compute_create_classes(GUPnPDIDLLiteContainer *container)
return g_variant_builder_end(&create_classes_vb);
}
-const gchar *dls_props_media_spec_to_upnp_class(const gchar *m2spec_class)
+static const gchar *prv_media_spec_to_upnp_class(const gchar *m2spec_class)
{
const gchar *retval = NULL;
- if (!m2spec_class)
- goto on_error;
-
- if (!strcmp(m2spec_class, gMediaSpec2AlbumPhoto))
- retval = gUPnPPhotoAlbum;
- else if (!strcmp(m2spec_class, gMediaSpec2AlbumMusic))
- retval = gUPnPMusicAlbum;
- else if (!strcmp(m2spec_class, gMediaSpec2Album))
- retval = gUPnPAlbum;
- else if (!strcmp(m2spec_class, gMediaSpec2PersonMusicArtist))
- retval = gUPnPMusicArtist;
- else if (!strcmp(m2spec_class, gMediaSpec2Person))
- retval = gUPnPPerson;
- else if (!strcmp(m2spec_class, gMediaSpec2GenreMovie))
- retval = gUPnPMovieGenre;
- else if (!strcmp(m2spec_class, gMediaSpec2GenreMusic))
- retval = gUPnPMusicGenre;
- else if (!strcmp(m2spec_class, gMediaSpec2Genre))
- retval = gUPnPGenre;
- else if (!strcmp(m2spec_class, gMediaSpec2Container))
+ if (!strcmp(m2spec_class, gMediaSpec2Container))
retval = gUPnPContainer;
else if (!strcmp(m2spec_class, gMediaSpec2AudioMusic))
retval = gUPnPMusicTrack;
- else if (!strcmp(m2spec_class, gMediaSpec2AudioBroadcast))
- retval = gUPnPAudioBroadcast;
- else if (!strcmp(m2spec_class, gMediaSpec2AudioBook))
- retval = gUPnPAudioBook;
else if (!strcmp(m2spec_class, gMediaSpec2Audio))
retval = gUPnPAudioItem;
else if (!strcmp(m2spec_class, gMediaSpec2VideoMovie))
retval = gUPnPMovie;
- else if (!strcmp(m2spec_class, gMediaSpec2VideoMusicClip))
- retval = gUPnPMusicVideoClip;
- else if (!strcmp(m2spec_class, gMediaSpec2VideoBroadcast))
- retval = gUPnPVideoBroadcast;
else if (!strcmp(m2spec_class, gMediaSpec2Video))
retval = gUPnPVideoItem;
else if (!strcmp(m2spec_class, gMediaSpec2ImagePhoto))
retval = gUPnPPhoto;
else if (!strcmp(m2spec_class, gMediaSpec2Image))
retval = gUPnPImageItem;
- else if (!strcmp(m2spec_class, gMediaSpec2Playlist))
- retval = gUPnPPlaylist;
- else if (!strcmp(m2spec_class, gMediaSpec2PlaylistItem))
- retval = gUPnPPlaylistItem;
- else if (!strcmp(m2spec_class, gMediaSpec2Item))
+
+ return retval;
+}
+
+const gchar *dls_props_media_spec_to_upnp_class(const gchar *m2spec_class)
+{
+ const gchar *retval = NULL;
+
+ if (!m2spec_class)
+ goto on_error;
+
+ retval = prv_media_spec_to_upnp_class(m2spec_class);
+
+ if (!retval && !strcmp(m2spec_class, gMediaSpec2ItemUnclassified))
retval = gUPnPItem;
- else if (!strcmp(m2spec_class, gMediaSpec2Storage))
- retval = gUPnPStorage;
on_error:
return retval;
}
-const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class)
+gchar *dls_props_media_spec_ex_to_upnp_class(const gchar *m2spec_class)
+{
+ gchar *retval = NULL;
+ const gchar *basic_type;
+ const gchar *ptr = NULL;
+
+ if (!m2spec_class)
+ goto on_error;
+
+ basic_type = prv_media_spec_to_upnp_class(m2spec_class);
+ if (basic_type) {
+ retval = g_strdup(basic_type);
+ } else {
+ if (!strncmp(m2spec_class, gMediaSpec2ExItem,
+ gMediaSpec2ExItemLen))
+ ptr = m2spec_class + gMediaSpec2ExItemLen;
+ else if (!strncmp(m2spec_class, gMediaSpec2Container,
+ gMediaSpec2ContainerLen))
+ ptr = m2spec_class + gMediaSpec2ContainerLen;
+ if (ptr && (!*ptr || *ptr == '.'))
+ retval = g_strdup_printf("object.%s", m2spec_class);
+ }
+
+on_error:
+
+ return retval;
+}
+
+static const gchar *prv_upnp_class_to_media_spec(const gchar *upnp_class,
+ gboolean *exact)
{
const gchar *retval = NULL;
const gchar *ptr;
@@ -1227,71 +1207,73 @@ const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class)
if (!upnp_class)
goto on_error;
- if (!strncmp(upnp_class, gUPnPAlbum, gUPnPAlbumLen)) {
- ptr = upnp_class + gUPnPAlbumLen;
- if (!strcmp(ptr, ".photoAlbum"))
- retval = gMediaSpec2AlbumPhoto;
- else if (!strcmp(ptr, ".musicAlbum"))
- retval = gMediaSpec2AlbumMusic;
- else
- retval = gMediaSpec2Album;
- } else if (!strncmp(upnp_class, gUPnPPerson, gUPnPPersonLen)) {
- ptr = upnp_class + gUPnPPersonLen;
- if (!strcmp(ptr, ".musicArtist"))
- retval = gMediaSpec2PersonMusicArtist;
- else
- retval = gMediaSpec2Person;
- } else if (!strncmp(upnp_class, gUPnPGenre, gUPnPGenreLen)) {
- ptr = upnp_class + gUPnPGenreLen;
- if (!strcmp(ptr, ".movieGenre"))
- retval = gMediaSpec2GenreMovie;
- else if (!strcmp(ptr, ".musicGenre"))
- retval = gMediaSpec2GenreMusic;
- else
- retval = gMediaSpec2Genre;
- } else if (!strncmp(upnp_class, gUPnPContainer, gUPnPContainerLen)) {
+ if (!strncmp(upnp_class, gUPnPContainer, gUPnPContainerLen)) {
ptr = upnp_class + gUPnPContainerLen;
- if (!*ptr || *ptr == '.')
+ if (!*ptr || *ptr == '.') {
retval = gMediaSpec2Container;
+ *exact = *ptr == 0;
+ }
} else if (!strncmp(upnp_class, gUPnPAudioItem, gUPnPAudioItemLen)) {
ptr = upnp_class + gUPnPAudioItemLen;
- if (!strcmp(ptr, ".musicTrack"))
+ if (!strcmp(ptr, ".musicTrack")) {
retval = gMediaSpec2AudioMusic;
- else if (!strcmp(ptr, ".audioBroadcast"))
- retval = gMediaSpec2AudioBroadcast;
- else if (!strcmp(ptr, ".audioBook"))
- retval = gMediaSpec2AudioBook;
- else
+ *exact = TRUE;
+ } else if (!*ptr || *ptr == '.') {
retval = gMediaSpec2Audio;
+ *exact = *ptr == 0;
+ }
} else if (!strncmp(upnp_class, gUPnPVideoItem, gUPnPVideoItemLen)) {
ptr = upnp_class + gUPnPVideoItemLen;
- if (!strcmp(ptr, ".movie"))
+ if (!strcmp(ptr, ".movie")) {
retval = gMediaSpec2VideoMovie;
- else if (!strcmp(ptr, ".musicVideoClip"))
- retval = gMediaSpec2VideoMusicClip;
- else if (!strcmp(ptr, ".videoBroadcast"))
- retval = gMediaSpec2VideoBroadcast;
- else
+ *exact = TRUE;
+ } else if (!*ptr || *ptr == '.') {
retval = gMediaSpec2Video;
+ *exact = *ptr == 0;
+ }
} else if (!strncmp(upnp_class, gUPnPImageItem, gUPnPImageItemLen)) {
ptr = upnp_class + gUPnPImageItemLen;
- if (!strcmp(ptr, ".photo"))
+ if (!strcmp(ptr, ".photo")) {
retval = gMediaSpec2ImagePhoto;
- else
+ *exact = TRUE;
+ } else if (!*ptr || *ptr == '.') {
retval = gMediaSpec2Image;
- } else if (!strncmp(upnp_class, gUPnPPlaylist,
- gUPnPPlaylistLen)) {
- retval = gMediaSpec2Playlist;
- } else if (!strncmp(upnp_class, gUPnPPlaylistItem,
- gUPnPPlaylistItemLen)) {
- retval = gMediaSpec2PlaylistItem;
+ *exact = *ptr == 0;
+ }
} else if (!strncmp(upnp_class, gUPnPItem, gUPnPItemLen)) {
ptr = upnp_class + gUPnPItemLen;
- if (!*ptr || *ptr == '.')
- retval = gMediaSpec2Item;
- } else if (!strncmp(upnp_class, gUPnPStorage,
- gUPnPStorageLen)) {
- retval = gMediaSpec2Storage;
+ if (!*ptr || *ptr == '.') {
+ retval = gMediaSpec2ItemUnclassified;
+ *exact = *ptr == 0;
+ }
+ }
+
+on_error:
+
+ return retval;
+}
+
+const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class)
+{
+ gboolean exact;
+
+ return prv_upnp_class_to_media_spec(upnp_class, &exact);
+}
+
+const gchar *dls_props_upnp_class_to_media_spec_ex(const gchar *upnp_class)
+{
+ const gchar *retval;
+ gboolean exact;
+
+ retval = prv_upnp_class_to_media_spec(upnp_class, &exact);
+ if (!retval)
+ goto on_error;
+
+ if (exact) {
+ if (retval == gMediaSpec2ItemUnclassified)
+ retval = gMediaSpec2ExItem;
+ } else {
+ retval = upnp_class + gUPnPObjectLen + 1;
}
on_error:
@@ -1368,6 +1350,7 @@ gboolean dls_props_add_object(GVariantBuilder *item_vb,
const char *creator;
const char *upnp_class;
const char *media_spec_type;
+ const char *media_spec_type_ex;
gboolean retval = FALSE;
gboolean rest;
GUPnPOCMFlags flags;
@@ -1383,6 +1366,8 @@ gboolean dls_props_add_object(GVariantBuilder *item_vb,
if (!media_spec_type)
goto on_error;
+ media_spec_type_ex = dls_props_upnp_class_to_media_spec_ex(upnp_class);
+
title = gupnp_didl_lite_object_get_title(object);
creator = gupnp_didl_lite_object_get_creator(object);
rest = gupnp_didl_lite_object_get_restricted(object);
@@ -1407,6 +1392,10 @@ gboolean dls_props_add_object(GVariantBuilder *item_vb,
prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_TYPE,
media_spec_type);
+ if (filter_mask & DLS_UPNP_MASK_PROP_TYPE_EX)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_TYPE_EX,
+ media_spec_type_ex);
+
if (filter_mask & DLS_UPNP_MASK_PROP_RESTRICTED)
prv_add_bool_prop(item_vb, DLS_INTERFACE_PROP_RESTRICTED, rest);
@@ -1785,6 +1774,17 @@ GVariant *dls_props_get_object_prop(const gchar *prop, const gchar *root_path,
retval = g_variant_ref_sink(g_variant_new_string(
media_spec_type));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE_EX)) {
+ upnp_class = gupnp_didl_lite_object_get_upnp_class(object);
+ media_spec_type =
+ dls_props_upnp_class_to_media_spec_ex(upnp_class);
+ if (!media_spec_type)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, media_spec_type);
+
+ retval = g_variant_ref_sink(g_variant_new_string(
+ media_spec_type));
} else if (!strcmp(prop, DLS_INTERFACE_PROP_DISPLAY_NAME)) {
title = gupnp_didl_lite_object_get_title(object);
if (!title)
diff --git a/libdleyna/server/props.h b/libdleyna/server/props.h
index f219573..c4628f5 100644
--- a/libdleyna/server/props.h
+++ b/libdleyna/server/props.h
@@ -64,6 +64,7 @@
#define DLS_UPNP_MASK_PROP_DLNA_CONVERSION (1LL << 35)
#define DLS_UPNP_MASK_PROP_DLNA_OPERATION (1LL << 36)
#define DLS_UPNP_MASK_PROP_DLNA_FLAGS (1LL << 37)
+#define DLS_UPNP_MASK_PROP_TYPE_EX (1LL << 38)
#define DLS_UPNP_MASK_ALL_PROPS 0xffffffffffffffff
@@ -134,6 +135,10 @@ GVariant *dls_props_get_item_prop(const gchar *prop, const gchar *root_path,
const gchar *dls_props_media_spec_to_upnp_class(const gchar *m2spec_class);
+gchar *dls_props_media_spec_ex_to_upnp_class(const gchar *m2spec_class);
+
const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class);
+const gchar *dls_props_upnp_class_to_media_spec_ex(const gchar *upnp_class);
+
#endif /* DLS_PROPS_H__ */
diff --git a/libdleyna/server/search.c b/libdleyna/server/search.c
index 264654e..c331ceb 100644
--- a/libdleyna/server/search.c
+++ b/libdleyna/server/search.c
@@ -37,6 +37,7 @@ gchar *dls_search_translate_search_string(GHashTable *filter_map,
gchar *op = NULL;
gchar *value = NULL;
const gchar *translated_value;
+ gchar *translated_type_ex;
dls_prop_map_t *prop_map;
GString *str;
gint start_pos;
@@ -80,6 +81,18 @@ gchar *dls_search_translate_search_string(GHashTable *filter_map,
goto on_error;
g_free(value);
value = g_strdup_printf("\"%s\"", translated_value);
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE_EX)) {
+ /* Skip the quotes */
+
+ value[strlen(value) - 1] = 0;
+ translated_type_ex =
+ dls_props_media_spec_ex_to_upnp_class(
+ value + 1);
+ if (!translated_type_ex)
+ goto on_error;
+ g_free(value);
+ value = g_strdup_printf("\"%s\"", translated_type_ex);
+ g_free(translated_type_ex);
} else if (!strcmp(prop, DLS_INTERFACE_PROP_PARENT) ||
!strcmp(prop, DLS_INTERFACE_PROP_PATH)) {
value[strlen(value) - 1] = 0;
diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c
index 4db03e4..caa4701 100644
--- a/libdleyna/server/server.c
+++ b/libdleyna/server/server.c
@@ -120,6 +120,8 @@ static const gchar g_server_introspection[] =
" access='read'/>"
" <property type='s' name='"DLS_INTERFACE_PROP_TYPE"'"
" access='read'/>"
+ " <property type='s' name='"DLS_INTERFACE_PROP_TYPE_EX"'"
+ " access='read'/>"
" <property type='o' name='"DLS_INTERFACE_PROP_PATH"'"
" access='read'/>"
" <property type='s' name='"DLS_INTERFACE_PROP_DISPLAY_NAME"'"