MiniDLNA update: 1.0.19.1 to 1.0.20
[tomato.git] / release / src / router / minidlna / playlist.c
blobfadd4e3d0e57707b22e466c401d70a4b7d3892e3
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>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
29 #include "tagutils/tagutils.h"
31 #include "upnpglobalvars.h"
32 #include "scanner.h"
33 #include "metadata.h"
34 #include "utils.h"
35 #include "sql.h"
36 #include "log.h"
38 int
39 insert_playlist(const char * path, char * name)
41 struct song_metadata plist;
42 struct stat file;
43 int items = 0, matches, ret;
44 char type[4];
46 strncpy(type, strrchr(name, '.')+1, 4);
48 if( start_plist(path, NULL, &file, NULL, type) != 0 )
50 DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path);
51 return -1;
53 while( (ret = next_plist_track(&plist, &file, NULL, type)) == 0 )
55 items++;
56 freetags(&plist);
58 if( ret == 2 ) // Bad playlist -- contains binary characters
60 DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path);
61 return -1;
63 strip_ext(name);
65 DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", name, items);
67 matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", name);
68 if( matches > 0 )
70 sql_exec(db, "INSERT into PLAYLISTS"
71 " (NAME, PATH, ITEMS) "
72 "VALUES"
73 " ('%q(%d)', '%q', %d)",
74 name, matches, path, items);
76 else
78 sql_exec(db, "INSERT into PLAYLISTS"
79 " (NAME, PATH, ITEMS) "
80 "VALUES"
81 " ('%q', '%q', %d)",
82 name, path, items);
84 return 0;
87 int
88 fill_playlists()
90 int rows, i, found, len;
91 char **result;
92 char *plpath, *plname, *fname;
93 char class[] = "playlistContainer";
94 struct song_metadata plist;
95 struct stat file;
96 char type[4];
97 sqlite_int64 plID, detailID;
98 char sql_buf[1024] = "SELECT ID, NAME, PATH from PLAYLISTS where ITEMS > FOUND";
100 if( sql_get_table(db, sql_buf, &result, &rows, NULL) != SQLITE_OK )
101 return -1;
102 if( !rows )
104 sqlite3_free_table(result);
105 return 0;
108 rows++;
109 for( i=3; i<rows*3; i++ )
111 plID = strtoll(result[i], NULL, 10);
112 plname = result[++i];
113 plpath = result[++i];
115 strncpy(type, strrchr(plpath, '.')+1, 4);
117 if( start_plist(plpath, NULL, &file, NULL, type) != 0 )
118 continue;
120 DPRINTF(E_DEBUG, L_SCANNER, "Scanning playlist \"%s\" [%s]\n", plname, plpath);
121 if( sql_get_int_field(db, "SELECT ID from OBJECTS where PARENT_ID = '"MUSIC_PLIST_ID"'"
122 " and NAME = '%q'", plname) <= 0 )
124 detailID = GetFolderMetadata(plname, NULL, NULL, NULL, NULL);
125 sql_exec(db, "INSERT into OBJECTS"
126 " (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME) "
127 "VALUES"
128 " ('%s$%llX', '%s', %lld, 'container.%s', '%q')",
129 MUSIC_PLIST_ID, plID, MUSIC_PLIST_ID, detailID, class, plname);
132 plpath = dirname(plpath);
133 found = 0;
134 while( next_plist_track(&plist, &file, NULL, type) == 0 )
136 if( sql_get_int_field(db, "SELECT 1 from OBJECTS where OBJECT_ID = '%s$%llX$%d'",
137 MUSIC_PLIST_ID, plID, plist.track) == 1 )
139 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%d: already in database\n", plist.track);
140 found++;
141 freetags(&plist);
142 continue;
145 fname = plist.path;
146 DPRINTF(E_DEBUG, L_SCANNER, "%d: checking database for %s\n", plist.track, plist.path);
147 if( !strpbrk(fname, "\\/") )
149 len = strlen(fname) + strlen(plpath) + 2;
150 plist.path = malloc(len);
151 snprintf(plist.path, len, "%s/%s", plpath, fname);
152 free(fname);
153 fname = plist.path;
155 else
157 while( *fname == '\\' )
159 fname++;
162 retry:
163 //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "* Searching for %s in db\n", fname);
164 detailID = sql_get_int_field(db, "SELECT ID from DETAILS where PATH like '%%%q'", fname);
165 if( detailID > 0 )
167 DPRINTF(E_DEBUG, L_SCANNER, "+ %s found in db\n", fname);
168 sql_exec(db, "INSERT into OBJECTS"
169 " (OBJECT_ID, PARENT_ID, CLASS, DETAIL_ID, NAME, REF_ID) "
170 "SELECT"
171 " '%s$%llX$%d', '%s$%llX', CLASS, DETAIL_ID, NAME, OBJECT_ID from OBJECTS"
172 " where DETAIL_ID = %lld and OBJECT_ID glob '" BROWSEDIR_ID "$*'",
173 MUSIC_PLIST_ID, plID, plist.track,
174 MUSIC_PLIST_ID, plID,
175 detailID);
176 found++;
178 else
180 DPRINTF(E_DEBUG, L_SCANNER, "- %s not found in db\n", fname);
181 if( strchr(fname, '\\') )
183 fname = modifyString(fname, "\\", "/", 0);
184 goto retry;
186 else if( (fname = strchr(fname, '/')) )
188 fname++;
189 goto retry;
192 freetags(&plist);
194 sql_exec(db, "UPDATE PLAYLISTS set FOUND = %d where ID = %lld", found, plID);
196 sqlite3_free_table(result);
198 return 0;