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/>.
26 #include <sys/types.h>
30 #include "tagutils/tagutils.h"
32 #include "upnpglobalvars.h"
40 insert_playlist(const char * path
, char * name
)
42 struct song_metadata plist
;
44 int items
= 0, matches
, ret
;
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
);
54 while( (ret
= next_plist_track(&plist
, &file
, NULL
, type
)) == 0 )
59 if( ret
== 2 ) // Bad playlist -- contains binary characters
61 DPRINTF(E_WARN
, L_SCANNER
, "Bad playlist [%s]\n", path
);
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
);
71 sql_exec(db
, "INSERT into PLAYLISTS"
72 " (NAME, PATH, ITEMS) "
74 " ('%q(%d)', '%q', %d)",
75 name
, matches
, path
, items
);
79 sql_exec(db
, "INSERT into PLAYLISTS"
80 " (NAME, PATH, ITEMS) "
89 gen_dir_hash(const char *path
)
91 char dir
[PATH_MAX
], *base
;
94 strncpy(dir
, path
, sizeof(dir
));
95 dir
[sizeof(dir
)-1] = '\0';
96 base
= strrchr(dir
, '/');
98 base
= strrchr(dir
, '\\');
108 return DJBHash(dir
, len
);
114 int rows
, i
, found
, len
;
116 char *plpath
, *plname
, *fname
, *last_dir
;
117 unsigned int hash
, last_hash
= 0;
118 char class[] = "playlistContainer";
119 struct song_metadata plist
;
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
)
131 sqlite3_free_table(result
);
136 for( i
=3; i
<rows
*3; i
++ )
138 plID
= strtoll(result
[i
], NULL
, 10);
139 plname
= result
[++i
];
140 plpath
= result
[++i
];
144 strncpy(type
, strrchr(plpath
, '.')+1, 4);
146 if( start_plist(plpath
, NULL
, &file
, NULL
, type
) != 0 )
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) "
157 " ('%s$%llX', '%s', %lld, 'container.%s', '%q')",
158 MUSIC_PLIST_ID
, plID
, MUSIC_PLIST_ID
, detailID
, class, plname
);
161 plpath
= dirname(plpath
);
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);
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
);
185 sqlite3_free(last_dir
);
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
);
204 while( *fname
== '\\' )
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
);
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) "
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
,
226 last_dir
= sql_get_text_field(db
, "SELECT PATH from DETAILS where ID = %lld", detailID
);
227 fname
= strrchr(last_dir
, '/');
236 DPRINTF(E_DEBUG
, L_SCANNER
, "- %s not found in db\n", fname
);
237 if( strchr(fname
, '\\') )
239 fname
= modifyString(fname
, "\\", "/", 0);
242 else if( (fname
= strchr(fname
, '/')) )
252 sqlite3_free(last_dir
);
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");