dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / minidlna / playlist.c
blob789b48c255276eb89cd382316c6a1478835af5b0
1 /* MiniDLNA media server
2 * Copyright (C) 2009-2010 Justin Maggard
4 * This file is part of MiniDLNA.
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.
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.
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/>.
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <sys/stat.h>
22 #include <libgen.h>
23 #include <limits.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
30 #include "tagutils/tagutils.h"
32 #include "upnpglobalvars.h"
33 #include "scanner.h"
34 #include "metadata.h"
35 #include "utils.h"
36 #include "sql.h"
37 #include "log.h"
39 int
40 insert_playlist(const char * path, char * name)
42 struct song_metadata plist;
43 struct stat file;
44 int items = 0, matches, ret;
45 char type[4];
47 strncpy(type, strrchr(name, '.')+1, 4);
49 if( start_plist(path, NULL, &file, NULL, type) != 0 )
51 DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path);
52 return -1;
54 while( (ret = next_plist_track(&plist, &file, NULL, type)) == 0 )
56 items++;
57 freetags(&plist);
59 if( ret == 2 ) // Bad playlist -- contains binary characters
61 DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path);
62 return -1;
64 strip_ext(name);
66 DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", name, items);
68 matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", name);
69 if( matches > 0 )
71 sql_exec(db, "INSERT into PLAYLISTS"
72 " (NAME, PATH, ITEMS) "
73 "VALUES"
74 " ('%q(%d)', '%q', %d)",
75 name, matches, path, items);
77 else
79 sql_exec(db, "INSERT into PLAYLISTS"
80 " (NAME, PATH, ITEMS) "
81 "VALUES"
82 " ('%q', '%q', %d)",
83 name, path, items);
85 return 0;
88 static unsigned int
89 gen_dir_hash(const char *path)
91 char dir[PATH_MAX], *base;
92 int len;
94 strncpy(dir, path, sizeof(dir));
95 dir[sizeof(dir)-1] = '\0';
96 base = strrchr(dir, '/');
97 if( !base )
98 base = strrchr(dir, '\\');
99 if( base )
101 *base = '\0';
102 len = base - dir;
104 else
105 return 0;
108 return DJBHash(dir, len);
112 fill_playlists()
114 int rows, i, found, len;
115 char **result;
116 char *plpath, *plname, *fname, *last_dir;
117 unsigned int hash, last_hash = 0;
118 char class[] = "playlistContainer";
119 struct song_metadata plist;
120 struct stat file;
121 char type[4];
122 sqlite_int64 plID, detailID;
123 char sql_buf[] = "SELECT ID, NAME, PATH from PLAYLISTS where ITEMS > FOUND";
125 DPRINTF(E_WARN, L_SCANNER, "Parsing playlists...\n");
127 if( sql_get_table(db, sql_buf, &result, &rows, NULL) != SQLITE_OK )
128 return -1;
129 if( !rows )
131 sqlite3_free_table(result);
132 return 0;
135 rows++;
136 for( i=3; i<rows*3; i++ )
138 plID = strtoll(result[i], NULL, 10);
139 plname = result[++i];
140 plpath = result[++i];
141 last_dir = NULL;
142 last_hash = 0;
144 strncpy(type, strrchr(plpath, '.')+1, 4);
146 if( start_plist(plpath, NULL, &file, NULL, type) != 0 )
147 continue;
149 DPRINTF(E_DEBUG, L_SCANNER, "Scanning playlist \"%s\" [%s]\n", plname, plpath);
150 if( sql_get_int_field(db, "SELECT ID from OBJECTS where PARENT_ID = '"MUSIC_PLIST_ID"'"
151 " and NAME = '%q'", plname) <= 0 )
153 detailID = GetFolderMetadata(plname, NULL, NULL, NULL, 0);
154 sql_exec(db, "INSERT into OBJECTS"
155 " (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME) "
156 "VALUES"
157 " ('%s$%llX', '%s', %lld, 'container.%s', '%q')",
158 MUSIC_PLIST_ID, plID, MUSIC_PLIST_ID, detailID, class, plname);
161 plpath = dirname(plpath);
162 found = 0;
163 while( next_plist_track(&plist, &file, NULL, type) == 0 )
165 hash = gen_dir_hash(plist.path);
166 if( sql_get_int_field(db, "SELECT 1 from OBJECTS where OBJECT_ID = '%s$%llX$%d'",
167 MUSIC_PLIST_ID, plID, plist.track) == 1 )
169 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%d: already in database\n", plist.track);
170 found++;
171 freetags(&plist);
172 continue;
174 if( last_dir )
176 if( hash == last_hash )
178 fname = basename(plist.path);
179 detailID = sql_get_int_field(db, "SELECT ID from DETAILS where PATH = '%q/%q'", last_dir, fname);
181 else
182 detailID = -1;
183 if( detailID <= 0 )
185 sqlite3_free(last_dir);
186 last_dir = NULL;
188 else
189 goto found;
192 fname = plist.path;
193 DPRINTF(E_DEBUG, L_SCANNER, "%d: checking database for %s\n", plist.track, plist.path);
194 if( !strpbrk(fname, "\\/") )
196 len = strlen(fname) + strlen(plpath) + 2;
197 plist.path = malloc(len);
198 snprintf(plist.path, len, "%s/%s", plpath, fname);
199 free(fname);
200 fname = plist.path;
202 else
204 while( *fname == '\\' )
206 fname++;
209 retry:
210 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "* Searching for %s in db\n", fname);
211 detailID = sql_get_int_field(db, "SELECT ID from DETAILS where PATH like '%%%q'", fname);
212 if( detailID > 0 )
214 found:
215 DPRINTF(E_DEBUG, L_SCANNER, "+ %s found in db\n", fname);
216 sql_exec(db, "INSERT into OBJECTS"
217 " (OBJECT_ID, PARENT_ID, CLASS, DETAIL_ID, NAME, REF_ID) "
218 "SELECT"
219 " '%s$%llX$%d', '%s$%llX', CLASS, DETAIL_ID, NAME, OBJECT_ID from OBJECTS"
220 " where DETAIL_ID = %lld and OBJECT_ID glob '" BROWSEDIR_ID "$*'",
221 MUSIC_PLIST_ID, plID, plist.track,
222 MUSIC_PLIST_ID, plID,
223 detailID);
224 if( !last_dir )
226 last_dir = sql_get_text_field(db, "SELECT PATH from DETAILS where ID = %lld", detailID);
227 fname = strrchr(last_dir, '/');
228 if( fname )
229 *fname = '\0';
230 last_hash = hash;
232 found++;
234 else
236 DPRINTF(E_DEBUG, L_SCANNER, "- %s not found in db\n", fname);
237 if( strchr(fname, '\\') )
239 fname = modifyString(fname, "\\", "/", 0);
240 goto retry;
242 else if( (fname = strchr(fname, '/')) )
244 fname++;
245 goto retry;
248 freetags(&plist);
250 if( last_dir )
252 sqlite3_free(last_dir);
253 last_dir = NULL;
255 sql_exec(db, "UPDATE PLAYLISTS set FOUND = %d where ID = %lld", found, plID);
257 sqlite3_free_table(result);
258 DPRINTF(E_WARN, L_SCANNER, "Finished parsing playlists.\n");
260 return 0;