Add some video metadata support through libdlna (>0.2.3).
Some more changes for DLNA compliance. Reformat some other code.
This commit is contained in:
parent
a163077b29
commit
ccd9b957f6
2
Makefile
2
Makefile
@ -30,7 +30,7 @@ BASEOBJS = minidlna.o upnphttp.o upnpdescgen.o upnpsoap.o \
|
||||
ALLOBJS = $(BASEOBJS) $(LNXOBJS)
|
||||
|
||||
#LIBS = -liptc
|
||||
LIBS = -lexif -ltag_c -lsqlite3 #-lgd
|
||||
LIBS = -lexif -ltag_c -lsqlite3 -ldlna #-lgd
|
||||
|
||||
TESTUPNPDESCGENOBJS = testupnpdescgen.o upnpdescgen.o
|
||||
|
||||
|
114
metadata.c
114
metadata.c
@ -24,9 +24,11 @@
|
||||
#include <sqlite3.h>
|
||||
#include <taglib/tag_c.h>
|
||||
#include <libexif/exif-loader.h>
|
||||
#include <dlna.h>
|
||||
|
||||
#include "upnpglobalvars.h"
|
||||
#include "metadata.h"
|
||||
#include "sql.h"
|
||||
|
||||
#define FLAG_ARTIST 0x01
|
||||
|
||||
@ -98,6 +100,27 @@ strip_ext(char * name)
|
||||
*rindex(name, '.') = '\0';
|
||||
}
|
||||
|
||||
sqlite_int64
|
||||
GetFolderMetadata(const char * name, const char * artist)
|
||||
{
|
||||
char * sql;
|
||||
int ret;
|
||||
|
||||
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||
" (TITLE, ARTIST) "
|
||||
"VALUES"
|
||||
" ('%q', %Q);",
|
||||
name, artist);
|
||||
|
||||
if( sql_exec(db, sql) != SQLITE_OK )
|
||||
ret = 0;
|
||||
else
|
||||
ret = sqlite3_last_insert_rowid(db);
|
||||
sqlite3_free(sql);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sqlite_int64
|
||||
GetAudioMetadata(const char * path, char * name)
|
||||
{
|
||||
@ -258,16 +281,17 @@ GetImageMetadata(const char * path, char * name)
|
||||
ExifTag tag;
|
||||
int width=0, height=0, thumb=0;
|
||||
size_t size;
|
||||
char date[64], make[32], model[64], dlna_pn[64];
|
||||
char date[64], make[32], model[64];
|
||||
char b[1024];
|
||||
struct stat file;
|
||||
sqlite_int64 ret;
|
||||
char *sql;
|
||||
char *zErrMsg = NULL;
|
||||
metadata_t m;
|
||||
memset(&m, '\0', sizeof(metadata_t));
|
||||
|
||||
date[0] = '\0';
|
||||
model[0] = '\0';
|
||||
dlna_pn[0] = '\0';
|
||||
|
||||
//DEBUG printf("Parsing %s...\n", path);
|
||||
if ( stat(path, &file) == 0 )
|
||||
@ -277,6 +301,9 @@ GetImageMetadata(const char * path, char * name)
|
||||
strip_ext(name);
|
||||
//DEBUG printf(" * size: %d\n", size);
|
||||
|
||||
/* MIME hard-coded to JPEG for now, until we add PNG support */
|
||||
asprintf(&m.mime, "image/jpeg");
|
||||
|
||||
ExifLoader * l = exif_loader_new();
|
||||
exif_loader_write_file(l, path);
|
||||
ed = exif_loader_get_data(l);
|
||||
@ -340,19 +367,20 @@ GetImageMetadata(const char * path, char * name)
|
||||
exif_data_unref(ed);
|
||||
|
||||
if( width <= 640 && height <= 480 )
|
||||
strcpy(dlna_pn, "JPEG_SM;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
|
||||
asprintf(&m.dlna_pn, "JPEG_SM;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
|
||||
else if( width <= 1024 && height <= 768 )
|
||||
strcpy(dlna_pn, "JPEG_MED;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
|
||||
asprintf(&m.dlna_pn, "JPEG_MED;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
|
||||
else if( width <= 4096 && height <= 4096 )
|
||||
strcpy(dlna_pn, "JPEG_LRG;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
|
||||
asprintf(&m.dlna_pn, "JPEG_LRG;DLNA.ORG_OP=01;DLNA.ORG_CI=0");
|
||||
else
|
||||
strcpy(dlna_pn, "JPEG_XL");
|
||||
asprintf(&m.dlna_pn, "JPEG_XL");
|
||||
asprintf(&m.resolution, "%dx%d", width, height);
|
||||
|
||||
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||
" (TITLE, SIZE, DATE, WIDTH, HEIGHT, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
|
||||
" (TITLE, SIZE, DATE, RESOLUTION, THUMBNAIL, CREATOR, DLNA_PN, MIME) "
|
||||
"VALUES"
|
||||
" ('%q', %d, '%s', %d, %d, %d, '%q', '%s', '%s');",
|
||||
name, size, date, width, height, thumb, model, dlna_pn, "image/jpeg");
|
||||
" ('%q', %d, '%s', %Q, %d, '%q', %Q, %Q);",
|
||||
name, size, date, m.resolution, thumb, model, m.dlna_pn, m.mime);
|
||||
//DEBUG printf("SQL: %s\n", sql);
|
||||
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
|
||||
{
|
||||
@ -366,6 +394,12 @@ GetImageMetadata(const char * path, char * name)
|
||||
ret = sqlite3_last_insert_rowid(db);
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
if( m.resolution )
|
||||
free(m.resolution);
|
||||
if( m.dlna_pn )
|
||||
free(m.dlna_pn);
|
||||
if( m.mime )
|
||||
free(m.mime);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -374,9 +408,14 @@ GetVideoMetadata(const char * path, char * name)
|
||||
{
|
||||
size_t size = 0;
|
||||
struct stat file;
|
||||
dlna_t *dlna;
|
||||
dlna_profile_t *p;
|
||||
dlna_item_t *item;
|
||||
char *sql;
|
||||
char *zErrMsg = NULL;
|
||||
int ret;
|
||||
metadata_t m;
|
||||
memset(&m, '\0', sizeof(m));
|
||||
|
||||
//DEBUG printf("Parsing %s...\n", path);
|
||||
if ( stat(path, &file) == 0 )
|
||||
@ -384,11 +423,53 @@ GetVideoMetadata(const char * path, char * name)
|
||||
strip_ext(name);
|
||||
//DEBUG printf(" * size: %d\n", size);
|
||||
|
||||
dlna = dlna_init();
|
||||
dlna_register_all_media_profiles(dlna);
|
||||
|
||||
item = dlna_item_new (dlna, path);
|
||||
if (item)
|
||||
{
|
||||
if (item->properties)
|
||||
{
|
||||
if( strlen(item->properties->duration) )
|
||||
m.duration = item->properties->duration;
|
||||
if( item->properties->bitrate )
|
||||
asprintf(&m.bitrate, "%d", item->properties->bitrate);
|
||||
if( item->properties->sample_frequency )
|
||||
asprintf(&m.frequency, "%d", item->properties->sample_frequency);
|
||||
if( item->properties->bps )
|
||||
asprintf(&m.bps, "%d", item->properties->bps);
|
||||
if( item->properties->channels )
|
||||
asprintf(&m.channels, "%d", item->properties->channels);
|
||||
m.resolution = item->properties->resolution;
|
||||
}
|
||||
}
|
||||
|
||||
p = dlna_guess_media_profile (dlna, path);
|
||||
if (p)
|
||||
{
|
||||
m.mime = (char *)p->mime;
|
||||
asprintf(&m.dlna_pn, "%s;DLNA.ORG_OP=01;DLNA.ORG_CI=0", p->id);
|
||||
}
|
||||
else
|
||||
printf ("Unknown format [%s]\n", path);
|
||||
|
||||
sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||
" (SIZE, DURATION, CHANNELS, BITRATE, SAMPLERATE, RESOLUTION,"
|
||||
" TITLE, DLNA_PN, MIME) "
|
||||
"VALUES"
|
||||
" (%d, %Q, %d, %d, %d, %Q, '%q', %Q, '%q');",
|
||||
size, m.duration,
|
||||
item->properties ? item->properties->channels : 0,
|
||||
item->properties ? item->properties->bitrate : 0,
|
||||
item->properties ? item->properties->sample_frequency : 0,
|
||||
m.resolution, name,
|
||||
m.dlna_pn, m.mime);
|
||||
/* sql = sqlite3_mprintf( "INSERT into DETAILS"
|
||||
" (TITLE, SIZE, MIME) "
|
||||
"VALUES"
|
||||
" ('%q', %d, %Q);",
|
||||
name, size, "video/mpeg");
|
||||
name, size, "video/mpeg");*/
|
||||
//DEBUG printf("SQL: %s\n", sql);
|
||||
if( sqlite3_exec(db, sql, 0, 0, &zErrMsg) != SQLITE_OK )
|
||||
{
|
||||
@ -402,5 +483,18 @@ GetVideoMetadata(const char * path, char * name)
|
||||
ret = sqlite3_last_insert_rowid(db);
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
dlna_item_free(item);
|
||||
dlna_uninit(dlna);
|
||||
if( m.dlna_pn )
|
||||
free(m.dlna_pn);
|
||||
if( m.bitrate )
|
||||
free(m.bitrate);
|
||||
if( m.frequency )
|
||||
free(m.frequency);
|
||||
if( m.bps )
|
||||
free(m.bps);
|
||||
if( m.channels )
|
||||
free(m.channels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
19
metadata.h
19
metadata.h
@ -10,9 +10,28 @@
|
||||
#ifndef __METADATA_H__
|
||||
#define __METADATA_H__
|
||||
|
||||
typedef struct metadata_s {
|
||||
char *title;
|
||||
char *artist;
|
||||
char *album;
|
||||
char *genre;
|
||||
char *comment;
|
||||
char *channels;
|
||||
char *bitrate;
|
||||
char *frequency;
|
||||
char *bps;
|
||||
char *resolution;
|
||||
char *duration;
|
||||
char *mime;
|
||||
char *dlna_pn;
|
||||
} metadata_t;
|
||||
|
||||
char *
|
||||
modifyString(char * string, const char * before, const char * after, short like);
|
||||
|
||||
sqlite_int64
|
||||
GetFolderMetadata(const char * name, const char * artist);
|
||||
|
||||
sqlite_int64
|
||||
GetAudioMetadata(const char * path, char * name);
|
||||
|
||||
|
43
scanner.c
43
scanner.c
@ -58,13 +58,14 @@ is_image(const char * file)
|
||||
}
|
||||
|
||||
long long int
|
||||
insert_container(const char * tmpTable, const char * item, const char * rootParent, const char *subParent, const char *class, long unsigned int detailID)
|
||||
insert_container(const char * tmpTable, const char * item, const char * rootParent, const char *subParent, const char *class, const char *artist)
|
||||
{
|
||||
char **result;
|
||||
char *sql;
|
||||
int cols, rows, ret;
|
||||
char *zErrMsg = NULL;
|
||||
int parentID = 0, objectID = 0;
|
||||
sqlite_int64 detailID;
|
||||
|
||||
sql = sqlite3_mprintf("SELECT * from %s where ITEM = '%q' and SUBITEM = '%q'", tmpTable, item, subParent);
|
||||
ret = sql_get_table(db, sql, &result, &rows, &cols, &zErrMsg);
|
||||
@ -95,10 +96,11 @@ insert_container(const char * tmpTable, const char * item, const char * rootPare
|
||||
{
|
||||
parentID = 0;
|
||||
}
|
||||
detailID = GetFolderMetadata(item, artist);
|
||||
sql = sqlite3_mprintf( "INSERT into OBJECTS"
|
||||
" (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME) "
|
||||
"VALUES"
|
||||
" ('%s$%X', '%s', %lu, 'container.%s', '%q')",
|
||||
" ('%s$%X', '%s', %lld, 'container.%s', '%q')",
|
||||
rootParent, parentID, rootParent, detailID, class, item);
|
||||
ret = sql_exec(db, sql);
|
||||
sqlite3_free(sql);
|
||||
@ -136,7 +138,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
|
||||
strncpy(date_taken, date, 10);
|
||||
if( date )
|
||||
{
|
||||
container = insert_container("DATES", date_taken, "3$12", NULL, "album.photoAlbum", 0);
|
||||
container = insert_container("DATES", date_taken, "3$12", NULL, "album.photoAlbum", NULL);
|
||||
parentID = container>>32;
|
||||
objectID = container;
|
||||
sql = sqlite3_mprintf( "INSERT into OBJECTS"
|
||||
@ -149,12 +151,12 @@ insert_containers(const char * name, const char *path, const char * refID, const
|
||||
}
|
||||
if( cam && date )
|
||||
{
|
||||
container = insert_container("CAMS", cam, "3$13", NULL, "storageFolder", 0);
|
||||
container = insert_container("CAMS", cam, "3$13", NULL, "storageFolder", NULL);
|
||||
parentID = container>>32;
|
||||
//objectID = container;
|
||||
char parent[64];
|
||||
sprintf(parent, "3$13$%X", parentID);
|
||||
long long int subcontainer = insert_container("CAMDATE", date_taken, parent, cam, "storageFolder", 0);
|
||||
long long int subcontainer = insert_container("CAMDATE", date_taken, parent, cam, "storageFolder", NULL);
|
||||
int subParentID = subcontainer>>32;
|
||||
int subObjectID = subcontainer;
|
||||
sql = sqlite3_mprintf( "INSERT into OBJECTS"
|
||||
@ -195,7 +197,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
|
||||
else
|
||||
{
|
||||
strcpy(last_artist, artist);
|
||||
container = insert_container("ARTISTS", artist, "1$6", NULL, "person.musicArtist", 0);
|
||||
container = insert_container("ARTISTS", artist, "1$6", NULL, "person.musicArtist", NULL);
|
||||
parentID = container>>32;
|
||||
objectID = container;
|
||||
last_artist_objectID = objectID;
|
||||
@ -219,7 +221,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
|
||||
else
|
||||
{
|
||||
strcpy(last_album, album);
|
||||
container = insert_container("ALBUMS", album, "1$7", NULL, "album.musicAlbum", detailID);
|
||||
container = insert_container("ALBUMS", album, "1$7", NULL, "album.musicAlbum", artist);
|
||||
parentID = container>>32;
|
||||
objectID = container;
|
||||
last_album_objectID = objectID;
|
||||
@ -243,7 +245,7 @@ insert_containers(const char * name, const char *path, const char * refID, const
|
||||
else
|
||||
{
|
||||
strcpy(last_genre, genre);
|
||||
container = insert_container("GENRES", genre, "1$5", NULL, "genre.musicGenre", 0);
|
||||
container = insert_container("GENRES", genre, "1$5", NULL, "genre.musicGenre", NULL);
|
||||
parentID = container>>32;
|
||||
objectID = container;
|
||||
last_genre_objectID = objectID;
|
||||
@ -272,22 +274,30 @@ insert_containers(const char * name, const char *path, const char * refID, const
|
||||
int
|
||||
insert_directory(const char * name, const char * path, const char * parentID, int objectID)
|
||||
{
|
||||
char *sql;
|
||||
char * sql;
|
||||
int ret, i;
|
||||
sqlite_int64 detailID;
|
||||
char * refID = NULL;
|
||||
char class[] = "container.storageFolder";
|
||||
const char * const base[] = { BROWSEDIR_ID, MUSIC_DIR_ID, VIDEO_DIR_ID, IMAGE_DIR_ID, 0 };
|
||||
|
||||
detailID = GetFolderMetadata(name, NULL);
|
||||
for( i=0; base[i]; i++ )
|
||||
{
|
||||
sql = sqlite3_mprintf( "INSERT into OBJECTS"
|
||||
" (OBJECT_ID, PARENT_ID, CLASS, PATH, NAME) "
|
||||
" (OBJECT_ID, PARENT_ID, REF_ID, DETAIL_ID, CLASS, PATH, NAME) "
|
||||
"VALUES"
|
||||
" ('%s%s$%X', '%s%s', '%s', '%q', '%q')",
|
||||
base[i], parentID, objectID, base[i], parentID, class, path, name);
|
||||
" ('%s%s$%X', '%s%s', %Q, '%lld', '%s', '%q', '%q')",
|
||||
base[i], parentID, objectID, base[i], parentID, refID, detailID, class, path, name);
|
||||
//DEBUG printf("SQL: %s\n", sql);
|
||||
ret = sql_exec(db, sql);
|
||||
sqlite3_free(sql);
|
||||
if( !i )
|
||||
asprintf(&refID, "%s%s$%X", base[0], parentID, objectID);
|
||||
}
|
||||
if( refID )
|
||||
free(refID);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -401,8 +411,7 @@ create_database(void)
|
||||
"CHANNELS INTEGER, "
|
||||
"TRACK INTEGER, "
|
||||
"DATE DATE, "
|
||||
"WIDTH TEXT, "
|
||||
"HEIGHT TEXT, "
|
||||
"RESOLUTION TEXT, "
|
||||
"THUMBNAIL BOOL DEFAULT 0, "
|
||||
"CREATOR TEXT, "
|
||||
"DLNA_PN TEXT, "
|
||||
@ -412,8 +421,10 @@ create_database(void)
|
||||
goto sql_failed;
|
||||
for( i=0; containers[i]; i=i+3 )
|
||||
{
|
||||
sprintf(sql_buf, "INSERT into OBJECTS (OBJECT_ID, PARENT_ID, CLASS, NAME) values ( '%s', '%s', 'container.storageFolder', '%s')",
|
||||
containers[i], containers[i+1], containers[i+2]);
|
||||
sprintf(sql_buf, "INSERT into OBJECTS (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME)"
|
||||
" values "
|
||||
"('%s', '%s', %lld, 'container.storageFolder', '%s')",
|
||||
containers[i], containers[i+1], GetFolderMetadata(containers[i+2], NULL), containers[i+2]);
|
||||
ret = sql_exec(db, sql_buf);
|
||||
if( ret != SQLITE_OK )
|
||||
goto sql_failed;
|
||||
|
11
upnphttp.c
11
upnphttp.c
@ -195,7 +195,7 @@ printf("Range Start-End: %lld-%lld\n", h->req_RangeStart, h->req_RangeEnd);
|
||||
p = colon + 1;
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
if( strcmp(p, "1") != 0 )
|
||||
if( (*p != '1') || !isspace(p[1]) )
|
||||
h->reqflags |= FLAG_INVALID_REQ;
|
||||
}
|
||||
else if(strncasecmp(line, "TimeSeekRange.dlna.org", 22)==0)
|
||||
@ -549,6 +549,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
||||
HttpVer[i] = '\0';
|
||||
syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
|
||||
HttpCommand, HttpUrl, HttpVer);
|
||||
//DEBUG printf("HTTP REQUEST:\n%s\n", h->req_buf);
|
||||
ParseHttpHeaders(h);
|
||||
|
||||
if( (h->reqflags & FLAG_CHUNKED) && (h->req_chunklen > (h->req_buflen - h->req_contentoff) || h->req_chunklen < 0) )
|
||||
@ -567,7 +568,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
||||
{
|
||||
if( ((strcmp(h->HttpVer, "HTTP/1.1")==0) && !(h->reqflags & FLAG_HOST)) || (h->reqflags & FLAG_INVALID_REQ) )
|
||||
{
|
||||
syslog(LOG_NOTICE, "No Host specified in HTTP headers, responding ERROR 400");
|
||||
syslog(LOG_NOTICE, "Invalid request, responding ERROR 400. (No Host specified in HTTP headers?)");
|
||||
Send400(h);
|
||||
}
|
||||
else if( h->reqflags & FLAG_TIMESEEK )
|
||||
@ -1181,7 +1182,11 @@ SendResp_dlnafile(struct upnphttp * h, char * object)
|
||||
}
|
||||
else //if( h->reqflags & FLAG_XFERINTERACTIVE )
|
||||
{
|
||||
strcat(header, "transferMode.dlna.org: Interactive\r\n");
|
||||
if( (strncmp(mime, "vide", 4) == 0) ||
|
||||
(strncmp(mime, "audi", 4) == 0) )
|
||||
strcat(header, "transferMode.dlna.org: Streaming\r\n");
|
||||
else
|
||||
strcat(header, "transferMode.dlna.org: Interactive\r\n");
|
||||
}
|
||||
|
||||
sprintf(hdr_buf, "Accept-Ranges: bytes\r\n"
|
||||
|
84
upnpsoap.c
84
upnpsoap.c
@ -22,6 +22,7 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "upnpglobalvars.h"
|
||||
@ -30,9 +31,8 @@
|
||||
#include "upnpreplyparse.h"
|
||||
#include "getifaddr.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include "metadata.h"
|
||||
#include <sqlite3.h>
|
||||
#include "sql.h"
|
||||
|
||||
static void
|
||||
BuildSendAndCloseSoapResp(struct upnphttp * h,
|
||||
@ -254,14 +254,12 @@ GetCurrentConnectionInfo(struct upnphttp * h, const char * action)
|
||||
static int callback(void *args, int argc, char **argv, char **azColName)
|
||||
{
|
||||
struct Response { char *resp; int returned; int requested; int total; char *filter; } *passed_args = (struct Response *)args;
|
||||
char *id = argv[1], *parent = argv[2], *refID = argv[3], *class = argv[4], *name = argv[7], *size = argv[9],
|
||||
*title = argv[10], *duration = argv[11], *bitrate = argv[12], *sampleFrequency = argv[13],
|
||||
*artist = argv[14], *album = argv[15], *genre = argv[16], *comment = argv[17], *nrAudioChannels = argv[18],
|
||||
*track = argv[19], *date = argv[20], *width = argv[21], *height = argv[22], *tn = argv[23],
|
||||
*creator = argv[24], *dlna_pn = argv[25], *mime = argv[26];
|
||||
char *id = argv[1], *parent = argv[2], *refID = argv[3], *class = argv[4], *size = argv[9], *title = argv[10],
|
||||
*duration = argv[11], *bitrate = argv[12], *sampleFrequency = argv[13], *artist = argv[14], *album = argv[15],
|
||||
*genre = argv[16], *comment = argv[17], *nrAudioChannels = argv[18], *track = argv[19], *date = argv[20],
|
||||
*resolution = argv[21], *tn = argv[22], *creator = argv[23], *dlna_pn = argv[24], *mime = argv[25];
|
||||
char dlna_buf[64];
|
||||
char str_buf[4096];
|
||||
//char * str_buf = malloc(4096);
|
||||
char **result;
|
||||
int ret;
|
||||
|
||||
@ -269,20 +267,13 @@ static int callback(void *args, int argc, char **argv, char **azColName)
|
||||
|
||||
if( passed_args->requested && (passed_args->returned >= passed_args->requested) )
|
||||
return 0;
|
||||
//if( (strncmp(class, "item", 4) == 0) && !mime ) // Useless listing if there is no MIME type
|
||||
// return 0;
|
||||
passed_args->returned++;
|
||||
|
||||
if( dlna_pn )
|
||||
//sprintf(dlna_buf, "DLNA.ORG_PN=%s;DLNA.ORG_OP=01", dlna_pn);
|
||||
sprintf(dlna_buf, "DLNA.ORG_PN=%s", dlna_pn);
|
||||
else
|
||||
strcpy(dlna_buf, "*");
|
||||
|
||||
/*for(i=0; i<argc; i++){
|
||||
printf("%s = %s\n", azColName[i], argv[i]);
|
||||
}*/
|
||||
//printf("\n");
|
||||
if( strncmp(class, "item", 4) == 0 )
|
||||
{
|
||||
sprintf(str_buf, "<item id=\"%s\" parentID=\"%s\" restricted=\"1\"", id, parent);
|
||||
@ -294,7 +285,7 @@ static int callback(void *args, int argc, char **argv, char **azColName)
|
||||
sprintf(str_buf, ">"
|
||||
"<dc:title>%s</dc:title>"
|
||||
"<upnp:class>object.%s</upnp:class>",
|
||||
title?title:name, class);
|
||||
title, class);
|
||||
strcat(passed_args->resp, str_buf);
|
||||
if( comment && (!passed_args->filter || strstr(passed_args->filter, "dc:description")) ) {
|
||||
sprintf(str_buf, "<dc:description>%s</dc:description>", comment);
|
||||
@ -346,8 +337,8 @@ static int callback(void *args, int argc, char **argv, char **azColName)
|
||||
sprintf(str_buf, "nrAudioChannels=\"%s\" ", nrAudioChannels);
|
||||
strcat(passed_args->resp, str_buf);
|
||||
}
|
||||
if( width && height && (!passed_args->filter || strstr(passed_args->filter, "res@resolution")) ) {
|
||||
sprintf(str_buf, "resolution=\"%sx%s\" ", width, height);
|
||||
if( resolution && (!passed_args->filter || strstr(passed_args->filter, "res@resolution")) ) {
|
||||
sprintf(str_buf, "resolution=\"%s\" ", resolution);
|
||||
strcat(passed_args->resp, str_buf);
|
||||
}
|
||||
sprintf(str_buf, "protocolInfo=\"http-get:*:%s:%s\">"
|
||||
@ -382,15 +373,24 @@ static int callback(void *args, int argc, char **argv, char **azColName)
|
||||
ret = sqlite3_get_table(db, str_buf, &result, 0, 0, 0);
|
||||
sprintf(str_buf, "<container id=\"%s\" parentID=\"%s\" restricted=\"1\" ", id, parent);
|
||||
strcat(passed_args->resp, str_buf);
|
||||
if( !passed_args->filter || strstr(passed_args->filter, "@childCount")) {
|
||||
if( !passed_args->filter || strstr(passed_args->filter, "@childCount"))
|
||||
{
|
||||
sprintf(str_buf, "childCount=\"%s\"", result[1]);
|
||||
strcat(passed_args->resp, str_buf);
|
||||
}
|
||||
/* If the client calls for BrowseMetadata on root, we have to include our "upnp:searchClass"'s */
|
||||
if( (passed_args->requested == 1) && (strcmp(id, "0") == 0) )
|
||||
{
|
||||
strcat(passed_args->resp, ">"
|
||||
"<upnp:searchClass includeDerived=\"1\">object.item.audioItem</upnp:searchClass>"
|
||||
"<upnp:searchClass includeDerived=\"1\">object.item.imageItem</upnp:searchClass>"
|
||||
"<upnp:searchClass includeDerived=\"1\">object.item.videoItem</upnp:searchClass");
|
||||
}
|
||||
sprintf(str_buf, ">"
|
||||
"<dc:title>%s</dc:title>"
|
||||
"<upnp:class>object.%s</upnp:class>"
|
||||
"</container>",
|
||||
name, class);
|
||||
title, class);
|
||||
sqlite3_free_table(result);
|
||||
}
|
||||
strcat(passed_args->resp, str_buf);
|
||||
@ -410,15 +410,10 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
||||
static const char resp2[] = "<UpdateID>0</UpdateID></u:BrowseResponse>";
|
||||
|
||||
char *resp = calloc(1, 1048576);
|
||||
strcpy(resp, resp0);
|
||||
|
||||
char str_buf[4096];
|
||||
char str_buf2[4096];
|
||||
memset(str_buf, '\0', sizeof(str_buf));
|
||||
memset(str_buf2, '\0', sizeof(str_buf2));
|
||||
char *zErrMsg = 0;
|
||||
char *sql;
|
||||
int ret;
|
||||
char sql_buf[4096];
|
||||
struct Response { char *resp; int returned; int requested; int total; char *filter; } args;
|
||||
|
||||
struct NameValueParserData data;
|
||||
@ -432,8 +427,11 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
||||
if( !ObjectId )
|
||||
ObjectId = GetValueFromNameValueList(&data, "ContainerID");
|
||||
|
||||
memset(str_buf, '\0', sizeof(str_buf));
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.total = 0;
|
||||
strcpy(resp, resp0);
|
||||
|
||||
args.total = StartingIndex;
|
||||
args.returned = 0;
|
||||
args.requested = RequestedCount;
|
||||
args.resp = NULL;
|
||||
@ -458,16 +456,17 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
|
||||
if( strcmp(BrowseFlag, "BrowseMetadata") == 0 )
|
||||
{
|
||||
args.requested = 1;
|
||||
sprintf(sql_buf, "SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where OBJECT_ID = '%s';", ObjectId);
|
||||
ret = sqlite3_exec(db, sql_buf, callback, (void *) &args, &zErrMsg);
|
||||
sql = sqlite3_mprintf("SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where OBJECT_ID = '%s';", ObjectId);
|
||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(sql_buf, "SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||
" where PARENT_ID = '%s' order by d.TRACK, d.TITLE, o.NAME limit %d, -1;",
|
||||
ObjectId, StartingIndex);
|
||||
ret = sqlite3_exec(db, sql_buf, callback, (void *) &args, &zErrMsg);
|
||||
sql = sqlite3_mprintf("SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||
" where PARENT_ID = '%s' order by d.TRACK, d.TITLE, o.NAME limit %d, -1;",
|
||||
ObjectId, StartingIndex);
|
||||
ret = sqlite3_exec(db, sql, callback, (void *) &args, &zErrMsg);
|
||||
}
|
||||
sqlite3_free(sql);
|
||||
if( ret != SQLITE_OK ){
|
||||
printf("SQL error: %s\n", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
@ -492,13 +491,11 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
||||
static const char resp1[] = "</DIDL-Lite></Result>";
|
||||
static const char resp2[] = "<UpdateID>0</UpdateID></u:SearchResponse>";
|
||||
|
||||
char *resp = calloc(8, 16384);
|
||||
strcpy(resp, resp0);
|
||||
|
||||
char *resp = calloc(1, 1048576);
|
||||
char *zErrMsg = 0;
|
||||
char sql_buf[4096];
|
||||
char str_buf[4096];
|
||||
char str_buf2[4096];
|
||||
memset(str_buf, '\0', sizeof(str_buf));
|
||||
memset(str_buf2, '\0', sizeof(str_buf2));
|
||||
int ret;
|
||||
struct Response { char *resp; int returned; int requested; int total; char *filter; } args;
|
||||
|
||||
struct NameValueParserData data;
|
||||
@ -510,7 +507,9 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
||||
char * SearchCriteria = GetValueFromNameValueList(&data, "SearchCriteria");
|
||||
char * SortCriteria = GetValueFromNameValueList(&data, "SortCriteria");
|
||||
|
||||
memset(str_buf, '\0', sizeof(str_buf));
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
args.total = 0;
|
||||
args.returned = 0;
|
||||
args.requested = RequestedCount;
|
||||
@ -523,6 +522,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
||||
printf("Asked for Filter: %s\n", Filter);
|
||||
if( SortCriteria ) printf("Asked for SortCriteria: %s\n", SortCriteria);
|
||||
|
||||
strcpy(resp, resp0);
|
||||
|
||||
if( !Filter )
|
||||
{
|
||||
ClearNameValueList(&data);
|
||||
@ -553,11 +554,8 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
|
||||
SearchCriteria = modifyString(SearchCriteria, "@refID", "REF_ID", 0);
|
||||
SearchCriteria = modifyString(SearchCriteria, "object.", "", 0);
|
||||
}
|
||||
printf("Asked for SearchCriteria: %s\n", SearchCriteria);
|
||||
printf("Translated SearchCriteria: %s\n", SearchCriteria);
|
||||
|
||||
char *zErrMsg = 0;
|
||||
int ret;
|
||||
char sql_buf[4096];
|
||||
args.resp = resp;
|
||||
sprintf(sql_buf, "SELECT * from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID)"
|
||||
" where OBJECT_ID like '%s$%%' and (%s) order by d.TRACK, d.TITLE, o.NAME limit %d, -1;",
|
||||
|
Loading…
x
Reference in New Issue
Block a user