Mercurial > pt1.oyama
annotate src/metadata.c @ 146:066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
| author | Naoya OYAMA <naoya.oyama@gmail.com> |
|---|---|
| date | Tue, 21 Aug 2012 04:21:11 +0900 |
| parents | 2a9ac5ce2c7e |
| children | 30e91361506a |
| rev | line source |
|---|---|
| 125 | 1 /* -*- tab-width: 4; indent-tabs-mode: nil -*- */ |
| 2 /* vim: set ts=4 sts=4 sw=4 expandtab number : */ | |
| 3 /* | |
| 4 * metadata.c : GeeXboX uShare CDS Metadata DB. | |
| 5 * Originally developped for the GeeXboX project. | |
| 6 * Copyright (C) 2005-2007 Benjamin Zores <ben@geexbox.org> | |
| 7 * | |
| 8 * This program is free software; you can redistribute it and/or modify | |
| 9 * it under the terms of the GNU General Public License as published by | |
| 10 * the Free Software Foundation; either version 2 of the License, or | |
| 11 * (at your option) any later version. | |
| 12 * | |
| 13 * This program is distributed in the hope that it will be useful, | |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 * GNU Library General Public License for more details. | |
| 17 * | |
| 18 * You should have received a copy of the GNU General Public License along | |
| 19 * with this program; if not, write to the Free Software Foundation, | |
| 20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 21 */ | |
| 22 | |
| 23 #include <stdlib.h> | |
| 24 #include <string.h> | |
| 25 #include <stdio.h> | |
| 26 #include <dirent.h> | |
| 27 #include <sys/types.h> | |
| 28 #include <sys/stat.h> | |
| 29 #include <unistd.h> | |
| 30 #include <stdbool.h> | |
| 31 | |
|
136
2a9ac5ce2c7e
Remove internal libdlna and libupnp.(using OS package by default)
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
126
diff
changeset
|
32 #include <upnp.h> |
|
2a9ac5ce2c7e
Remove internal libdlna and libupnp.(using OS package by default)
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
126
diff
changeset
|
33 #include <upnptools.h> |
| 125 | 34 |
| 35 #include "mime.h" | |
| 36 #include "metadata.h" | |
| 37 #include "util_iconv.h" | |
| 38 #include "content.h" | |
| 39 #include "gettext.h" | |
| 40 #include "trace.h" | |
| 41 | |
| 42 #define TITLE_UNKNOWN "unknown" | |
| 43 | |
| 44 #define MAX_URL_SIZE 32 | |
| 45 | |
| 46 struct upnp_entry_lookup_t { | |
| 47 int id; | |
| 48 struct upnp_entry_t *entry_ptr; | |
| 49 }; | |
| 50 | |
| 51 static char * | |
| 52 getExtension (const char *filename) | |
| 53 { | |
| 54 char *str = NULL; | |
| 55 | |
| 56 str = strrchr (filename, '.'); | |
| 57 if (str) | |
| 58 str++; | |
| 59 | |
| 60 return str; | |
| 61 } | |
| 62 | |
| 63 static struct mime_type_t * | |
| 64 getMimeType (const char *extension) | |
| 65 { | |
| 66 extern struct mime_type_t MIME_Type_List[]; | |
| 67 struct mime_type_t *list; | |
| 68 | |
| 69 if (!extension) | |
| 70 return NULL; | |
| 71 | |
| 72 list = MIME_Type_List; | |
| 73 while (list->extension) | |
| 74 { | |
| 75 if (!strcasecmp (list->extension, extension)) | |
| 76 return list; | |
| 77 list++; | |
| 78 } | |
| 79 | |
| 80 return NULL; | |
| 81 } | |
| 82 | |
| 83 static bool | |
| 84 is_valid_extension (const char *extension) | |
| 85 { | |
| 86 if (!extension) | |
| 87 return false; | |
| 88 | |
| 89 if (getMimeType (extension)) | |
| 90 return true; | |
| 91 | |
| 92 return false; | |
| 93 } | |
| 94 | |
| 95 static int | |
| 96 get_list_length (void *list) | |
| 97 { | |
| 98 void **l = list; | |
| 99 int n = 0; | |
| 100 | |
| 101 while (*(l++)) | |
| 102 n++; | |
| 103 | |
| 104 return n; | |
| 105 } | |
| 106 | |
| 107 static xml_convert_t xml_convert[] = { | |
| 108 {'"' , """}, | |
| 109 {'&' , "&"}, | |
| 110 {'\'', "'"}, | |
| 111 {'<' , "<"}, | |
| 112 {'>' , ">"}, | |
| 113 {'\n', "
"}, | |
| 114 {'\r', "
"}, | |
| 115 {'\t', "	"}, | |
| 116 {0, NULL}, | |
| 117 }; | |
| 118 | |
| 119 static char * | |
| 120 get_xmlconvert (int c) | |
| 121 { | |
| 122 int j; | |
| 123 for (j = 0; xml_convert[j].xml; j++) | |
| 124 { | |
| 125 if (c == xml_convert[j].charac) | |
| 126 return xml_convert[j].xml; | |
| 127 } | |
| 128 return NULL; | |
| 129 } | |
| 130 | |
| 131 static char * | |
| 132 convert_xml (const char *title) | |
| 133 { | |
| 134 char *newtitle, *s, *t, *xml; | |
| 135 int nbconvert = 0; | |
| 136 | |
| 137 /* calculate extra size needed */ | |
| 138 for (t = (char*) title; *t; t++) | |
| 139 { | |
| 140 xml = get_xmlconvert (*t); | |
| 141 if (xml) | |
| 142 nbconvert += strlen (xml) - 1; | |
| 143 } | |
| 144 if (!nbconvert) | |
| 145 return NULL; | |
| 146 | |
| 147 newtitle = s = (char*) malloc (strlen (title) + nbconvert + 1); | |
| 148 | |
| 149 for (t = (char*) title; *t; t++) | |
| 150 { | |
| 151 xml = get_xmlconvert (*t); | |
| 152 if (xml) | |
| 153 { | |
| 154 strcpy (s, xml); | |
| 155 s += strlen (xml); | |
| 156 } | |
| 157 else | |
| 158 *s++ = *t; | |
| 159 } | |
| 160 *s = '\0'; | |
| 161 | |
| 162 return newtitle; | |
| 163 } | |
| 164 | |
| 165 static struct mime_type_t Container_MIME_Type = | |
| 166 { NULL, "object.container.storageFolder", NULL}; | |
| 167 | |
| 168 static struct upnp_entry_t * | |
| 169 upnp_entry_new (struct ushare_t *ut, const char *name, const char *fullpath, | |
| 170 struct upnp_entry_t *parent, off_t size, int dir) | |
| 171 { | |
| 172 struct upnp_entry_t *entry = NULL; | |
| 173 char *title = NULL, *x = NULL; | |
| 174 char url_tmp[MAX_URL_SIZE] = { '\0' }; | |
| 175 char *title_or_name = NULL; | |
| 176 | |
| 177 if (!name) | |
| 178 return NULL; | |
| 179 | |
| 180 entry = (struct upnp_entry_t *) malloc (sizeof (struct upnp_entry_t)); | |
| 181 | |
| 182 #ifdef HAVE_DLNA | |
| 183 // dlna_profile_t $B$rYTB$(B | |
| 184 entry->dlna_profile = NULL; | |
| 185 entry->url = NULL; | |
| 186 if (ut->dlna_enabled && fullpath && !dir) | |
| 187 { | |
| 188 dlna_profile_t *p = malloc(sizeof(dlna_profile_t)); | |
| 189 p->id = "MPEG_TS_HD_60_L2_ISO;DLNA.ORG_OP=01;"; | |
| 190 p->mime = "video/mpeg"; | |
| 191 p->label = "label"; | |
| 192 p->class = DLNA_CLASS_AV; | |
| 193 #if 0 | |
| 194 dlna_profile_t *p = dlna_guess_media_profile (ut->dlna, fullpath); | |
| 195 if (!p) | |
| 196 { | |
| 197 free (entry); | |
| 198 return NULL; | |
| 199 } | |
| 200 #endif | |
| 201 entry->dlna_profile = p; | |
| 202 } | |
| 203 #endif /* HAVE_DLNA */ | |
| 204 | |
| 205 if (ut->xbox360) | |
| 206 { | |
| 207 if (ut->root_entry) | |
| 208 entry->id = ut->starting_id + ut->nr_entries++; | |
| 209 else | |
| 210 entry->id = 0; /* Creating the root node so don't use the usual IDs */ | |
| 211 } | |
| 212 else | |
| 213 entry->id = ut->starting_id + ut->nr_entries++; | |
| 214 log_verbose ("upnp_entry_new(), entry->id[%d]\n", entry->id); | |
| 215 | |
| 216 entry->fullpath = fullpath ? strdup (fullpath) : NULL; | |
| 217 entry->parent = parent; | |
| 218 entry->child_count = dir ? 0 : -1; | |
| 219 entry->title = NULL; | |
| 220 | |
| 221 entry->childs = (struct upnp_entry_t **) | |
| 222 malloc (sizeof (struct upnp_entry_t *)); | |
| 223 *(entry->childs) = NULL; | |
| 224 | |
| 225 if (!dir) /* item */ | |
| 226 { | |
| 227 #if 0 | |
| 228 #ifdef HAVE_DLNA | |
| 229 if (ut->dlna_enabled) | |
| 230 entry->mime_type = NULL; | |
| 231 else | |
| 232 { | |
| 233 #endif /* HAVE_DLNA */ | |
| 234 #endif | |
| 235 struct mime_type_t *mime = getMimeType (getExtension (name)); | |
| 236 if (!mime) | |
| 237 { | |
| 238 --ut->nr_entries; | |
| 239 upnp_entry_free (ut, entry); | |
| 240 log_error ("Invalid Mime type for %s, entry ignored", name); | |
| 241 return NULL; | |
| 242 } | |
| 243 entry->mime_type = mime; | |
| 244 #if 0 | |
| 245 #ifdef HAVE_DLNA | |
| 246 } | |
| 247 #endif /* HAVE_DLNA */ | |
| 248 #endif | |
| 249 | |
| 250 if (snprintf (url_tmp, MAX_URL_SIZE, "%d.%s", | |
| 251 entry->id, getExtension (name)) >= MAX_URL_SIZE) | |
| 252 log_error ("URL string too long for id %d, truncated!!", entry->id); | |
| 253 | |
| 254 /* Only malloc() what we really need */ | |
| 255 entry->url = strdup (url_tmp); | |
| 256 } | |
| 257 else /* container */ | |
| 258 { | |
| 259 entry->mime_type = &Container_MIME_Type; | |
| 260 entry->url = NULL; | |
| 261 } | |
| 262 | |
| 263 /* Try Iconv'ing the name but if it fails the end device | |
| 264 may still be able to handle it */ | |
| 265 title = iconv_convert (name); | |
| 266 if (title) | |
| 267 title_or_name = title; | |
| 268 else | |
| 269 { | |
| 270 if (ut->override_iconv_err) | |
| 271 { | |
| 272 title_or_name = strdup (name); | |
| 273 log_error ("Entry invalid name id=%d [%s]\n", entry->id, name); | |
| 274 } | |
| 275 else | |
| 276 { | |
| 277 upnp_entry_free (ut, entry); | |
| 278 log_error ("Freeing entry invalid name id=%d [%s]\n", entry->id, name); | |
| 279 return NULL; | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 if (!dir) | |
| 284 { | |
| 285 x = strrchr (title_or_name, '.'); | |
| 286 if (x) /* avoid displaying file extension */ | |
| 287 *x = '\0'; | |
| 288 } | |
| 289 x = convert_xml (title_or_name); | |
| 290 if (x) | |
| 291 { | |
| 292 free (title_or_name); | |
| 293 title_or_name = x; | |
| 294 } | |
| 295 entry->title = title_or_name; | |
| 296 | |
| 297 if (!strcmp (title_or_name, "")) /* DIDL dc:title can't be empty */ | |
| 298 { | |
| 299 free (title_or_name); | |
| 300 entry->title = strdup (TITLE_UNKNOWN); | |
| 301 } | |
| 302 | |
| 303 entry->size = size; | |
| 304 entry->fd = -1; | |
| 305 | |
| 306 if (entry->id && entry->url) | |
| 307 log_verbose ("Entry->URL (%d): %s\n", entry->id, entry->url); | |
| 308 | |
| 309 return entry; | |
| 310 } | |
| 311 | |
| 312 /* Seperate recursive free() function in order to avoid freeing off | |
| 313 * the parents child list within the freeing of the first child, as | |
| 314 * the only entry which is not part of a childs list is the root entry | |
| 315 */ | |
| 316 static void | |
| 317 _upnp_entry_free (struct upnp_entry_t *entry) | |
| 318 { | |
| 319 struct upnp_entry_t **childs; | |
| 320 | |
| 321 if (!entry) | |
| 322 return; | |
| 323 | |
| 324 if (entry->fullpath) | |
| 325 free (entry->fullpath); | |
| 326 if (entry->title) | |
| 327 free (entry->title); | |
| 328 if (entry->url) | |
| 329 free (entry->url); | |
| 330 #ifdef HAVE_DLNA | |
| 331 if (entry->dlna_profile) | |
| 332 entry->dlna_profile = NULL; | |
| 333 #endif /* HAVE_DLNA */ | |
| 334 | |
| 335 for (childs = entry->childs; *childs; childs++) | |
| 336 _upnp_entry_free (*childs); | |
| 337 free (entry->childs); | |
| 338 } | |
| 339 | |
| 340 void | |
| 341 upnp_entry_free (struct ushare_t *ut, struct upnp_entry_t *entry) | |
| 342 { | |
| 343 if (!ut || !entry) | |
| 344 return; | |
| 345 | |
| 346 /* Free all entries (i.e. children) */ | |
| 347 if (entry == ut->root_entry) | |
| 348 { | |
| 349 struct upnp_entry_t *entry_found = NULL; | |
| 350 struct upnp_entry_lookup_t *lk = NULL; | |
| 351 RBLIST *rblist; | |
| 352 int i = 0; | |
| 353 | |
| 354 rblist = rbopenlist (ut->rb); | |
| 355 lk = (struct upnp_entry_lookup_t *) rbreadlist (rblist); | |
| 356 | |
| 357 while (lk) | |
| 358 { | |
| 359 entry_found = lk->entry_ptr; | |
| 360 if (entry_found) | |
| 361 { | |
| 362 if (entry_found->fullpath) | |
| 363 free (entry_found->fullpath); | |
| 364 if (entry_found->title) | |
| 365 free (entry_found->title); | |
| 366 if (entry_found->url) | |
| 367 free (entry_found->url); | |
| 368 | |
| 369 free (entry_found); | |
| 370 i++; | |
| 371 } | |
| 372 | |
| 373 free (lk); /* delete the lookup */ | |
| 374 lk = (struct upnp_entry_lookup_t *) rbreadlist (rblist); | |
| 375 } | |
| 376 | |
| 377 rbcloselist (rblist); | |
| 378 rbdestroy (ut->rb); | |
| 379 ut->rb = NULL; | |
| 380 | |
| 381 log_verbose ("Freed [%d] entries\n", i); | |
| 382 } | |
| 383 else | |
| 384 _upnp_entry_free (entry); | |
| 385 | |
| 386 free (entry); | |
| 387 } | |
| 388 | |
| 389 static void | |
| 390 upnp_entry_add_child (struct ushare_t *ut, | |
| 391 struct upnp_entry_t *entry, struct upnp_entry_t *child) | |
| 392 { | |
| 393 struct upnp_entry_lookup_t *entry_lookup_ptr = NULL; | |
| 394 struct upnp_entry_t **childs; | |
| 395 int n; | |
| 396 | |
| 397 if (!entry || !child) | |
| 398 return; | |
| 399 | |
| 400 for (childs = entry->childs; *childs; childs++) | |
| 401 if (*childs == child) | |
| 402 return; | |
| 403 | |
| 404 n = get_list_length ((void *) entry->childs) + 1; | |
| 405 entry->childs = (struct upnp_entry_t **) | |
| 406 realloc (entry->childs, (n + 1) * sizeof (*(entry->childs))); | |
| 407 entry->childs[n] = NULL; | |
| 408 entry->childs[n - 1] = child; | |
| 409 entry->child_count++; | |
| 410 | |
| 411 entry_lookup_ptr = (struct upnp_entry_lookup_t *) | |
| 412 malloc (sizeof (struct upnp_entry_lookup_t)); | |
| 413 entry_lookup_ptr->id = child->id; | |
| 414 entry_lookup_ptr->entry_ptr = child; | |
| 415 | |
| 416 if (rbsearch ((void *) entry_lookup_ptr, ut->rb) == NULL) | |
| 417 log_info (_("Failed to add the RB lookup tree\n")); | |
| 418 } | |
| 419 | |
| 420 struct upnp_entry_t * | |
| 421 upnp_get_entry (struct ushare_t *ut, int id) | |
| 422 { | |
| 423 struct upnp_entry_lookup_t *res, entry_lookup; | |
| 424 | |
| 425 log_verbose ("Looking for entry id %d\n", id); | |
| 426 if (id == 0) /* We do not store the root (id 0) as it is not a child */ | |
| 427 return ut->root_entry; | |
| 428 | |
| 429 entry_lookup.id = id; | |
| 430 res = (struct upnp_entry_lookup_t *) | |
| 431 rbfind ((void *) &entry_lookup, ut->rb); | |
| 432 | |
| 433 if (res) | |
| 434 { | |
| 435 log_verbose ("Found at %p\n", | |
| 436 ((struct upnp_entry_lookup_t *) res)->entry_ptr); | |
| 437 return ((struct upnp_entry_lookup_t *) res)->entry_ptr; | |
| 438 } | |
| 439 | |
| 440 log_verbose ("Not Found\n"); | |
| 441 | |
| 442 return NULL; | |
| 443 } | |
| 444 | |
| 445 static void | |
| 446 metadata_add_file (struct ushare_t *ut, struct upnp_entry_t *entry, | |
| 447 const char *file, const char *name, struct stat *st_ptr) | |
| 448 { | |
| 449 if (!entry || !file || !name) | |
| 450 return; | |
| 451 | |
| 452 #ifdef HAVE_DLNA | |
| 453 if (ut->dlna_enabled || is_valid_extension (getExtension (file))) | |
| 454 #else | |
| 455 if (is_valid_extension (getExtension (file))) | |
| 456 #endif | |
| 457 { | |
| 458 struct upnp_entry_t *child = NULL; | |
| 459 | |
| 460 child = upnp_entry_new (ut, name, file, entry, st_ptr->st_size, false); | |
| 461 if (child) | |
| 462 upnp_entry_add_child (ut, entry, child); | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 static void | |
| 467 metadata_add_container (struct ushare_t *ut, | |
| 468 struct upnp_entry_t *entry, const char *container) | |
| 469 { | |
| 470 struct dirent **namelist; | |
| 471 int n,i; | |
| 472 | |
| 473 if (!entry || !container) | |
| 474 return; | |
| 475 | |
| 476 n = scandir (container, &namelist, 0, alphasort); | |
| 477 if (n < 0) | |
| 478 { | |
| 479 perror ("scandir"); | |
| 480 return; | |
| 481 } | |
| 482 | |
| 483 for (i = 0; i < n; i++) | |
| 484 { | |
| 485 struct stat st; | |
| 486 char *fullpath = NULL; | |
| 487 | |
| 488 if (namelist[i]->d_name[0] == '.') | |
| 489 { | |
| 490 free (namelist[i]); | |
| 491 continue; | |
| 492 } | |
| 493 | |
| 494 fullpath = (char *) | |
| 495 malloc (strlen (container) + strlen (namelist[i]->d_name) + 2); | |
| 496 sprintf (fullpath, "%s/%s", container, namelist[i]->d_name); | |
| 497 | |
| 498 log_verbose ("%s\n", fullpath); | |
| 499 | |
| 500 if (stat (fullpath, &st) < 0) | |
| 501 { | |
| 502 free (namelist[i]); | |
| 503 free (fullpath); | |
| 504 continue; | |
| 505 } | |
| 506 | |
| 507 if (S_ISDIR (st.st_mode)) | |
| 508 { | |
| 509 struct upnp_entry_t *child = NULL; | |
| 510 | |
| 511 child = upnp_entry_new (ut, namelist[i]->d_name, | |
| 512 fullpath, entry, 0, true); | |
| 513 if (child) | |
| 514 { | |
| 515 metadata_add_container (ut, child, fullpath); | |
| 516 upnp_entry_add_child (ut, entry, child); | |
| 517 } | |
| 518 } | |
| 519 else | |
| 520 metadata_add_file (ut, entry, fullpath, namelist[i]->d_name, &st); | |
| 521 | |
| 522 free (namelist[i]); | |
| 523 free (fullpath); | |
| 524 } | |
| 525 free (namelist); | |
| 526 } | |
| 527 | |
| 528 void | |
| 529 free_metadata_list (struct ushare_t *ut) | |
| 530 { | |
| 531 ut->init = 0; | |
| 532 if (ut->root_entry) | |
| 533 upnp_entry_free (ut, ut->root_entry); | |
| 534 ut->root_entry = NULL; | |
| 535 ut->nr_entries = 0; | |
| 536 | |
| 537 if (ut->rb) | |
| 538 { | |
| 539 rbdestroy (ut->rb); | |
| 540 ut->rb = NULL; | |
| 541 } | |
| 542 | |
| 543 ut->rb = rbinit (rb_compare, NULL); | |
| 544 if (!ut->rb) | |
| 545 log_error (_("Cannot create RB tree for lookups\n")); | |
| 546 } | |
| 547 | |
| 548 void | |
| 549 build_metadata_list (struct ushare_t *ut) | |
| 550 { | |
| 551 int i; | |
| 552 struct stat st; | |
| 553 log_info (_("Building Metadata List ...\n")); | |
| 554 | |
| 555 /* build root entry */ | |
| 556 if (!ut->root_entry) | |
| 557 ut->root_entry = upnp_entry_new (ut, "root", NULL, NULL, -1, true); | |
| 558 | |
| 559 #if 0 | |
| 560 entry = upnp_entry_new (ut, "stream.ts", "/web/stream.ts", | |
| 561 ut->root_entry, -1, false); | |
| 562 upnp_entry_add_child (ut, ut->root_entry, entry); | |
| 563 metadata_add_container (ut, entry, "/web/"); | |
| 564 #endif | |
| 565 struct upnp_entry_t *entry = ut->root_entry; | |
| 566 st.st_size = 100*1024*1024; | |
|
146
066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
136
diff
changeset
|
567 if (ut->nr_channel == 0) { |
|
066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
136
diff
changeset
|
568 metadata_add_file (ut, ut->root_entry, STREAM_LOCATION, STREAM_FILE_NAME, &st); |
|
066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
136
diff
changeset
|
569 } else { |
|
066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
136
diff
changeset
|
570 for (i=0; i < ut->nr_channel; i++) |
|
066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
136
diff
changeset
|
571 metadata_add_file (ut, ut->root_entry, ut->location_name[i], ut->channel_name[i], &st); |
|
066f33b2213a
EXPERIMENTAL: Select a particular program from multi-channel.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
136
diff
changeset
|
572 } |
|
126
5dcaf3785ebe
fix process terminate problem.
Naoya OYAMA <naoya.oyama@gmail.com>
parents:
125
diff
changeset
|
573 ut->contentlist = NULL; |
| 125 | 574 //metadata_add_container (ut, ut->root_entry, "/web/"); |
| 575 | |
| 576 #if 0 | |
| 577 /* add files from content directory */ | |
| 578 for (i=0 ; i < ut->contentlist->count ; i++) | |
| 579 { | |
| 580 struct upnp_entry_t *entry = NULL; | |
| 581 char *title = NULL; | |
| 582 int size = 0; | |
| 583 | |
| 584 log_info (_("Looking for files in content directory : %s\n"), | |
| 585 ut->contentlist->content[i]); | |
| 586 | |
| 587 size = strlen (ut->contentlist->content[i]); | |
| 588 if (ut->contentlist->content[i][size - 1] == '/') | |
| 589 ut->contentlist->content[i][size - 1] = '\0'; | |
| 590 title = strrchr (ut->contentlist->content[i], '/'); | |
| 591 if (title) | |
| 592 title++; | |
| 593 else | |
| 594 { | |
| 595 /* directly use content directory name if no '/' before basename */ | |
| 596 title = ut->contentlist->content[i]; | |
| 597 } | |
| 598 | |
| 599 entry = upnp_entry_new (ut, title, ut->contentlist->content[i], | |
| 600 ut->root_entry, -1, true); | |
| 601 | |
| 602 if (!entry) | |
| 603 continue; | |
| 604 upnp_entry_add_child (ut, ut->root_entry, entry); | |
| 605 metadata_add_container (ut, entry, ut->contentlist->content[i]); | |
| 606 } | |
| 607 #endif | |
| 608 | |
| 609 log_info (_("Found %d files and subdirectories.\n"), ut->nr_entries); | |
| 610 ut->init = 1; | |
| 611 } | |
| 612 | |
| 613 int | |
| 614 rb_compare (const void *pa, const void *pb, | |
| 615 const void *config __attribute__ ((unused))) | |
| 616 { | |
| 617 struct upnp_entry_lookup_t *a, *b; | |
| 618 | |
| 619 a = (struct upnp_entry_lookup_t *) pa; | |
| 620 b = (struct upnp_entry_lookup_t *) pb; | |
| 621 | |
| 622 if (a->id < b->id) | |
| 623 return -1; | |
| 624 | |
| 625 if (a->id > b->id) | |
| 626 return 1; | |
| 627 | |
| 628 return 0; | |
| 629 } | |
| 630 |
