1/* MiniDLNA media server 2 * Copyright (C) 2014 NETGEAR 3 * 4 * This file is part of MiniDLNA. 5 * 6 * MiniDLNA is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * MiniDLNA is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>. 17 */ 18#include <string.h> 19#include "clients.h" 20#include "minidlnatypes.h" 21#include "scanner.h" 22#include "upnpglobalvars.h" 23#include "containers.h" 24#include "log.h" 25 26#define NINETY_DAYS "7776000" 27 28const char *music_id = MUSIC_ID; 29const char *music_all_id = MUSIC_ALL_ID; 30const char *music_genre_id = MUSIC_GENRE_ID; 31const char *music_artist_id = MUSIC_ARTIST_ID; 32const char *music_album_id = MUSIC_ALBUM_ID; 33const char *music_plist_id = MUSIC_PLIST_ID; 34const char *music_dir_id = MUSIC_DIR_ID; 35const char *video_all_id = VIDEO_ALL_ID; 36const char *video_dir_id = VIDEO_DIR_ID; 37const char *image_all_id = IMAGE_ALL_ID; 38const char *image_date_id = IMAGE_DATE_ID; 39const char *image_camera_id = IMAGE_CAMERA_ID; 40const char *image_dir_id = IMAGE_DIR_ID; 41 42struct magic_container_s magic_containers[] = 43{ 44 /* Alternate root container */ 45 { NULL, 46 "0", 47 &runtime_vars.root_container, 48 NULL, 49 "0", 50 NULL, 51 NULL, 52 NULL, 53 NULL, 54 -1, 55 0, 56 }, 57 58 /* Recent 50 audio items */ 59 { "Recently Added", 60 "1$FF0", 61 NULL, 62 "\"1$FF0$\" || OBJECT_ID", 63 "\"1$FF0\"", 64 "o.OBJECT_ID", 65 "(select null from DETAILS where MIME glob 'a*' and timestamp > (strftime('%s','now') - "NINETY_DAYS") limit 50)", 66 "MIME glob 'a*' and REF_ID is NULL and timestamp > (strftime('%s','now') - "NINETY_DAYS")", 67 "order by TIMESTAMP DESC", 68 50, 69 0, 70 }, 71 72 /* Recent 50 video items */ 73 { "Recently Added", 74 "2$FF0", 75 NULL, 76 "\"2$FF0$\" || OBJECT_ID", 77 "\"2$FF0\"", 78 "o.OBJECT_ID", 79 "(select null from DETAILS where MIME glob 'v*' and timestamp > (strftime('%s','now') - "NINETY_DAYS") limit 50)", 80 "MIME glob 'v*' and REF_ID is NULL and timestamp > (strftime('%s','now') - "NINETY_DAYS")", 81 "order by TIMESTAMP DESC", 82 50, 83 0, 84 }, 85 86 /* Recent 50 image items */ 87 { "Recently Added", 88 "3$FF0", 89 NULL, 90 "\"3$FF0$\" || OBJECT_ID", 91 "\"3$FF0\"", 92 "o.OBJECT_ID", 93 "(select null from DETAILS where MIME glob 'i*' and timestamp > (strftime('%s','now') - "NINETY_DAYS") limit 50)", 94 "MIME glob 'i*' and REF_ID is NULL and timestamp > (strftime('%s','now') - "NINETY_DAYS")", 95 "order by TIMESTAMP DESC", 96 50, 97 0, 98 }, 99 100 /* Microsoft PlaysForSure containers */ 101 { NULL, "4", &music_all_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 102 { NULL, "5", &music_genre_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 103 { NULL, "6", &music_artist_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 104 { NULL, "7", &music_album_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 105 { NULL, "8", &video_all_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 106 { NULL, "B", &image_all_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 107 { NULL, "C", &image_date_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 108 { NULL, "F", &music_plist_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 109 { NULL, "14", &music_dir_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 110 { NULL, "15", &video_dir_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 111 { NULL, "16", &image_dir_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 112 { NULL, "D2", &image_camera_id, NULL, NULL, NULL, NULL, NULL, NULL, -1, FLAG_MS_PFS }, 113 114 /* Jump straight to Music on audio-only devices */ 115 { NULL, "0", &music_id, NULL, "0", NULL, NULL, NULL, NULL, -1, FLAG_AUDIO_ONLY }, 116 117 { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0 } 118}; 119 120struct magic_container_s * 121in_magic_container(const char *id, int flags, const char **real_id) 122{ 123 size_t len; 124 int i; 125 126 for (i = 0; magic_containers[i].objectid_match; i++) 127 { 128 if (magic_containers[i].required_flags && !(flags & magic_containers[i].required_flags)) 129 continue; 130 if (magic_containers[i].objectid && !(*magic_containers[i].objectid)) 131 continue; 132 DPRINTF(E_MAXDEBUG, L_HTTP, "Checking magic container %d [%s]\n", i, magic_containers[i].objectid_match); 133 len = strlen(magic_containers[i].objectid_match); 134 if (strncmp(id, magic_containers[i].objectid_match, len) == 0) 135 { 136 if (*(id+len) == '$') 137 *real_id = id+len+1; 138 else if (*(id+len) == '\0') 139 *real_id = id; 140 else 141 continue; 142 DPRINTF(E_DEBUG, L_HTTP, "Found magic container %d [%s]\n", i, magic_containers[i].objectid_match); 143 return &magic_containers[i]; 144 } 145 } 146 147 return NULL; 148} 149 150struct magic_container_s * 151check_magic_container(const char *id, int flags) 152{ 153 int i; 154 155 for (i = 0; magic_containers[i].objectid_match; i++) 156 { 157 if (magic_containers[i].required_flags && !(flags & magic_containers[i].required_flags)) 158 continue; 159 if (magic_containers[i].objectid && !(*magic_containers[i].objectid)) 160 continue; 161 DPRINTF(E_MAXDEBUG, L_HTTP, "Checking magic container %d [%s]\n", i, magic_containers[i].objectid_match); 162 if (strcmp(id, magic_containers[i].objectid_match) == 0) 163 { 164 DPRINTF(E_DEBUG, L_HTTP, "Found magic container %d [%s]\n", i, magic_containers[i].objectid_match); 165 return &magic_containers[i]; 166 } 167 } 168 169 return NULL; 170} 171