source: titan/minidlna-1.0.22/scanner.c @ 13567

Last change on this file since 13567 was 13567, checked in by obi, 11 years ago

[titan] add minidlna-1.0.22 first step

File size: 26.3 KB
Line 
1/* MiniDLNA media server
2 * Copyright (C) 2008-2009  Justin Maggard
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 <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <dirent.h>
23#include <locale.h>
24#include <libgen.h>
25#include <inttypes.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <sys/resource.h>
29
30#include "config.h"
31
32#ifdef ENABLE_NLS
33#include <libintl.h>
34#endif
35#include <sqlite3.h>
36
37#include "upnpglobalvars.h"
38#include "metadata.h"
39#include "playlist.h"
40#include "utils.h"
41#include "sql.h"
42#include "scanner.h"
43#include "albumart.h"
44#include "log.h"
45
46int valid_cache = 0;
47
48struct virtual_item
49{
50        sqlite3_int64 objectID;
51        char parentID[64];
52        char name[256];
53};
54
55sqlite_int64
56get_next_available_id(const char * table, const char * parentID)
57{
58                char *ret, *base;
59                sqlite_int64 objectID = 0;
60
61                ret = sql_get_text_field(db, "SELECT OBJECT_ID from %s where ID = "
62                                             "(SELECT max(ID) from %s where PARENT_ID = '%s')",
63                                             table, table, parentID);
64                if( ret )
65                {
66                        base = strrchr(ret, '$');
67                        if( base )
68                                objectID = strtoll(base+1, NULL, 16) + 1;
69                        sqlite3_free(ret);
70                }
71
72                return objectID;
73}
74
75int
76insert_container(const char * item, const char * rootParent, const char * refID, const char *class,
77                 const char *artist, const char *genre, const char *album_art, sqlite3_int64 *objectID, sqlite3_int64 *parentID)
78{
79        char *result;
80        char *base;
81        int ret = 0;
82        sqlite_int64 detailID = 0;
83
84        result = sql_get_text_field(db, "SELECT OBJECT_ID from OBJECTS"
85                                        " where PARENT_ID = '%s'"
86                                        " and NAME = '%q'"
87                                        " and CLASS = 'container.%s' limit 1",
88                                        rootParent, item, class);
89        if( result )
90        {
91                base = strrchr(result, '$');
92                if( base )
93                        *parentID = strtoll(base+1, NULL, 16);
94                else
95                        *parentID = 0;
96                *objectID = get_next_available_id("OBJECTS", result);
97        }
98        else
99        {
100                *objectID = 0;
101                *parentID = get_next_available_id("OBJECTS", rootParent);
102                if( refID )
103                {
104                        result = sql_get_text_field(db, "SELECT DETAIL_ID from OBJECTS where OBJECT_ID = %Q", refID);
105                        if( result )
106                                detailID = strtoll(result, NULL, 10);
107                }
108                if( !detailID )
109                {
110                        detailID = GetFolderMetadata(item, NULL, artist, genre, (album_art ? strtoll(album_art, NULL, 10) : 0));
111                }
112                ret = sql_exec(db, "INSERT into OBJECTS"
113                                   " (OBJECT_ID, PARENT_ID, REF_ID, DETAIL_ID, CLASS, NAME) "
114                                   "VALUES"
115                                   " ('%s$%"PRIX64"', '%s', %Q, %"PRId64", 'container.%s', '%q')",
116                                   rootParent, *parentID, rootParent, refID, detailID, class, item);
117        }
118        sqlite3_free(result);
119
120        return ret;
121}
122
123static void
124insert_containers(const char * name, const char *path, const char * refID, const char * class, sqlite3_int64 detailID)
125{
126        char *sql;
127        char **result;
128        int ret;
129        int cols, row;
130        sqlite_int64 objectID, parentID;
131
132        if( strstr(class, "imageItem") )
133        {
134                char *date = NULL, *cam = NULL;
135                char date_taken[13], camera[64];
136                static struct virtual_item last_date;
137                static struct virtual_item last_cam;
138                static struct virtual_item last_camdate;
139                static sqlite_int64 last_all_objectID = 0;
140
141                asprintf(&sql, "SELECT DATE, CREATOR from DETAILS where ID = %"PRId64, detailID);
142                ret = sql_get_table(db, sql, &result, &row, &cols);
143                free(sql);
144                if( ret == SQLITE_OK )
145                {
146                        date = result[2];
147                        cam = result[3];
148                }
149
150                if( date )
151                {
152                        strncpy(date_taken, date, 10);
153                        date_taken[10] = '\0';
154                }
155                else
156                {
157                        strcpy(date_taken, _("Unknown Date"));
158                }
159                if( valid_cache && strcmp(last_date.name, date_taken) == 0 )
160                {
161                        last_date.objectID++;
162                        //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Using last date item: %s/%s/%X\n", last_date.name, last_date.parentID, last_date.objectID);
163                }
164                else
165                {
166                        insert_container(date_taken, IMAGE_DATE_ID, NULL, "album.photoAlbum", NULL, NULL, NULL, &objectID, &parentID);
167                        sprintf(last_date.parentID, IMAGE_DATE_ID"$%"PRIX64, parentID);
168                        last_date.objectID = objectID;
169                        strcpy(last_date.name, date_taken);
170                        //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Creating cached date item: %s/%s/%X\n", last_date.name, last_date.parentID, last_date.objectID);
171                }
172                sql_exec(db, "INSERT into OBJECTS"
173                             " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
174                             "VALUES"
175                             " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
176                             last_date.parentID, last_date.objectID, last_date.parentID, refID, class, detailID, name);
177
178                if( cam )
179                {
180                        strncpy(camera, cam, 63);
181                        camera[63] = '\0';
182                }
183                else
184                {
185                        strcpy(camera, _("Unknown Camera"));
186                }
187                if( !valid_cache || strcmp(camera, last_cam.name) != 0 )
188                {
189                        insert_container(camera, IMAGE_CAMERA_ID, NULL, "storageFolder", NULL, NULL, NULL, &objectID, &parentID);
190                        sprintf(last_cam.parentID, IMAGE_CAMERA_ID"$%"PRIX64, parentID);
191                        strncpy(last_cam.name, camera, 255);
192                        last_camdate.name[0] = '\0';
193                }
194                if( valid_cache && strcmp(last_camdate.name, date_taken) == 0 )
195                {
196                        last_camdate.objectID++;
197                        //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Using last camdate item: %s/%s/%s/%X\n", camera, last_camdate.name, last_camdate.parentID, last_camdate.objectID);
198                }
199                else
200                {
201                        insert_container(date_taken, last_cam.parentID, NULL, "album.photoAlbum", NULL, NULL, NULL, &objectID, &parentID);
202                        sprintf(last_camdate.parentID, "%s$%"PRIX64, last_cam.parentID, parentID);
203                        last_camdate.objectID = objectID;
204                        strcpy(last_camdate.name, date_taken);
205                        //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Creating cached camdate item: %s/%s/%s/%X\n", camera, last_camdate.name, last_camdate.parentID, last_camdate.objectID);
206                }
207                sql_exec(db, "INSERT into OBJECTS"
208                             " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
209                             "VALUES"
210                             " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
211                             last_camdate.parentID, last_camdate.objectID, last_camdate.parentID, refID, class, detailID, name);
212                /* All Images */
213                if( !last_all_objectID )
214                {
215                        last_all_objectID = get_next_available_id("OBJECTS", IMAGE_ALL_ID);
216                }
217                sql_exec(db, "INSERT into OBJECTS"
218                             " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
219                             "VALUES"
220                             " ('"IMAGE_ALL_ID"$%"PRIX64"', '"IMAGE_ALL_ID"', '%s', '%s', %"PRId64", %Q)",
221                             last_all_objectID++, refID, class, detailID, name);
222        }
223        else if( strstr(class, "audioItem") )
224        {
225                asprintf(&sql, "SELECT ALBUM, ARTIST, GENRE, ALBUM_ART from DETAILS where ID = %"PRId64, detailID);
226                ret = sql_get_table(db, sql, &result, &row, &cols);
227                free(sql);
228                if( ret != SQLITE_OK )
229                        return;
230                if( !row )
231                {
232                        sqlite3_free_table(result);
233                        return;
234                }
235                char *album = result[4], *artist = result[5], *genre = result[6];
236                char *album_art = result[7];
237                static struct virtual_item last_album;
238                static struct virtual_item last_artist;
239                static struct virtual_item last_artistAlbum;
240                static struct virtual_item last_artistAlbumAll;
241                static struct virtual_item last_genre;
242                static struct virtual_item last_genreArtist;
243                static struct virtual_item last_genreArtistAll;
244                static sqlite_int64 last_all_objectID = 0;
245
246                if( album )
247                {
248                        if( valid_cache && strcmp(album, last_album.name) == 0 )
249                        {
250                                last_album.objectID++;
251                                //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Using last album item: %s/%s/%X\n", last_album.name, last_album.parentID, last_album.objectID);
252                        }
253                        else
254                        {
255                                strcpy(last_album.name, album);
256                                insert_container(album, MUSIC_ALBUM_ID, NULL, "album.musicAlbum", artist, genre, album_art, &objectID, &parentID);
257                                sprintf(last_album.parentID, MUSIC_ALBUM_ID"$%llX", parentID);
258                                last_album.objectID = objectID;
259                                //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Creating cached album item: %s/%s/%X\n", last_album.name, last_album.parentID, last_album.objectID);
260                        }
261                        sql_exec(db, "INSERT into OBJECTS"
262                                     " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
263                                     "VALUES"
264                                     " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
265                                     last_album.parentID, last_album.objectID, last_album.parentID, refID, class, detailID, name);
266                }
267                if( artist )
268                {
269                        if( !valid_cache || strcmp(artist, last_artist.name) != 0 )
270                        {
271                                insert_container(artist, MUSIC_ARTIST_ID, NULL, "person.musicArtist", NULL, genre, NULL, &objectID, &parentID);
272                                sprintf(last_artist.parentID, MUSIC_ARTIST_ID"$%"PRIX64, parentID);
273                                strcpy(last_artist.name, artist);
274                                last_artistAlbum.name[0] = '\0';
275                                /* Add this file to the "- All Albums -" container as well */
276                                insert_container(_("- All Albums -"), last_artist.parentID, NULL, "album", artist, genre, NULL, &objectID, &parentID);
277                                sprintf(last_artistAlbumAll.parentID, "%s$%"PRIX64, last_artist.parentID, parentID);
278                                last_artistAlbumAll.objectID = objectID;
279                        }
280                        else
281                        {
282                                last_artistAlbumAll.objectID++;
283                        }
284                        if( valid_cache && strcmp(album?album:_("Unknown Album"), last_artistAlbum.name) == 0 )
285                        {
286                                last_artistAlbum.objectID++;
287                                //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Using last artist/album item: %s/%s/%X\n", last_artist.name, last_artist.parentID, last_artist.objectID);
288                        }
289                        else
290                        {
291                                insert_container(album?album:_("Unknown Album"), last_artist.parentID, album?last_album.parentID:NULL,
292                                                 "album.musicAlbum", artist, genre, album_art, &objectID, &parentID);
293                                sprintf(last_artistAlbum.parentID, "%s$%"PRIX64, last_artist.parentID, parentID);
294                                last_artistAlbum.objectID = objectID;
295                                strcpy(last_artistAlbum.name, album?album:_("Unknown Album"));
296                                //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Creating cached artist/album item: %s/%s/%X\n", last_artist.name, last_artist.parentID, last_artist.objectID);
297                        }
298                        sql_exec(db, "INSERT into OBJECTS"
299                                     " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
300                                     "VALUES"
301                                     " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
302                                     last_artistAlbum.parentID, last_artistAlbum.objectID, last_artistAlbum.parentID, refID, class, detailID, name);
303                        sql_exec(db, "INSERT into OBJECTS"
304                                     " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
305                                     "VALUES"
306                                     " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
307                                     last_artistAlbumAll.parentID, last_artistAlbumAll.objectID, last_artistAlbumAll.parentID, refID, class, detailID, name);
308                }
309                if( genre )
310                {
311                        if( !valid_cache || strcmp(genre, last_genre.name) != 0 )
312                        {
313                                insert_container(genre, MUSIC_GENRE_ID, NULL, "genre.musicGenre", NULL, NULL, NULL, &objectID, &parentID);
314                                sprintf(last_genre.parentID, MUSIC_GENRE_ID"$%"PRIX64, parentID);
315                                strcpy(last_genre.name, genre);
316                                last_genreArtist.name[0] = '\0';
317                                /* Add this file to the "- All Artists -" container as well */
318                                insert_container(_("- All Artists -"), last_genre.parentID, NULL, "person", NULL, genre, NULL, &objectID, &parentID);
319                                sprintf(last_genreArtistAll.parentID, "%s$%"PRIX64, last_genre.parentID, parentID);
320                                last_genreArtistAll.objectID = objectID;
321                        }
322                        else
323                        {
324                                last_genreArtistAll.objectID++;
325                        }
326                        if( valid_cache && strcmp(artist?artist:_("Unknown Artist"), last_genreArtist.name) == 0 )
327                        {
328                                last_genreArtist.objectID++;
329                        }
330                        else
331                        {
332                                insert_container(artist?artist:_("Unknown Artist"), last_genre.parentID, artist?last_artist.parentID:NULL,
333                                                 "person.musicArtist", NULL, genre, NULL, &objectID, &parentID);
334                                sprintf(last_genreArtist.parentID, "%s$%"PRIX64, last_genre.parentID, parentID);
335                                last_genreArtist.objectID = objectID;
336                                strcpy(last_genreArtist.name, artist?artist:_("Unknown Artist"));
337                                //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "Creating cached genre/artist item: %s/%s/%X\n", last_genreArtist.name, last_genreArtist.parentID, last_genreArtist.objectID);
338                        }
339                        sql_exec(db, "INSERT into OBJECTS"
340                                     " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
341                                     "VALUES"
342                                     " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
343                                     last_genreArtist.parentID, last_genreArtist.objectID, last_genreArtist.parentID, refID, class, detailID, name);
344                        sql_exec(db, "INSERT into OBJECTS"
345                                     " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
346                                     "VALUES"
347                                     " ('%s$%"PRIX64"', '%s', '%s', '%s', %"PRId64", %Q)",
348                                     last_genreArtistAll.parentID, last_genreArtistAll.objectID, last_genreArtistAll.parentID, refID, class, detailID, name);
349                }
350                /* All Music */
351                if( !last_all_objectID )
352                {
353                        last_all_objectID = get_next_available_id("OBJECTS", MUSIC_ALL_ID);
354                }
355                sql_exec(db, "INSERT into OBJECTS"
356                             " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
357                             "VALUES"
358                             " ('"MUSIC_ALL_ID"$%"PRIX64"', '"MUSIC_ALL_ID"', '%s', '%s', %"PRId64", %Q)",
359                             last_all_objectID++, refID, class, detailID, name);
360        }
361        else if( strstr(class, "videoItem") )
362        {
363                static sqlite_int64 last_all_objectID = 0;
364
365                /* All Videos */
366                if( !last_all_objectID )
367                {
368                        last_all_objectID = get_next_available_id("OBJECTS", VIDEO_ALL_ID);
369                }
370                sql_exec(db, "INSERT into OBJECTS"
371                             " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
372                             "VALUES"
373                             " ('"VIDEO_ALL_ID"$%"PRIX64"', '"VIDEO_ALL_ID"', '%s', '%s', %"PRId64", %Q)",
374                             last_all_objectID++, refID, class, detailID, name);
375                return;
376        }
377        else
378        {
379                return;
380        }
381        sqlite3_free_table(result);
382        valid_cache = 1;
383}
384
385int
386insert_directory(const char * name, const char * path, const char * base, const char * parentID, int objectID)
387{
388        int found = 0;
389        sqlite_int64 detailID = 0;
390        char * refID = NULL;
391        char class[] = "container.storageFolder";
392        char * id_buf = NULL;
393        char * parent_buf = NULL;
394        char *dir_buf, *dir;
395        char *result, *p;
396        static char last_found[256] = "-1";
397
398        if( strcmp(base, BROWSEDIR_ID) != 0 )
399                asprintf(&refID, "%s%s$%X", BROWSEDIR_ID, parentID, objectID);
400
401        if( refID )
402        {
403                dir_buf = strdup(path);
404                dir = dirname(dir_buf);
405                asprintf(&id_buf, "%s%s$%X", base, parentID, objectID);
406                asprintf(&parent_buf, "%s%s", base, parentID);
407                while( !found )
408                {
409                        if( strcmp(id_buf, last_found) == 0 )
410                                break;
411                        if( sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", id_buf) > 0 )
412                        {
413                                strcpy(last_found, id_buf);
414                                break;
415                        }
416                        /* Does not exist.  Need to create, and may need to create parents also */
417                        result = sql_get_text_field(db, "SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s'", refID);
418                        if( result )
419                        {
420                                detailID = strtoll(result, NULL, 10);
421                                sqlite3_free(result);
422                        }
423                        sql_exec(db, "INSERT into OBJECTS"
424                                     " (OBJECT_ID, PARENT_ID, REF_ID, DETAIL_ID, CLASS, NAME) "
425                                     "VALUES"
426                                     " ('%s', '%s', %Q, %"PRId64", '%s', '%q')",
427                                     id_buf, parent_buf, refID, detailID, class, strrchr(dir, '/')+1);
428                        if( (p = strrchr(id_buf, '$')) )
429                                *p = '\0';
430                        if( (p = strrchr(parent_buf, '$')) )
431                                *p = '\0';
432                        if( (p = strrchr(refID, '$')) )
433                                *p = '\0';
434                        dir = dirname(dir);
435                }
436                free(refID);
437                free(parent_buf);
438                free(id_buf);
439                free(dir_buf);
440                return 1;
441        }
442
443        detailID = GetFolderMetadata(name, path, NULL, NULL, find_album_art(path, NULL, 0));
444        sql_exec(db, "INSERT into OBJECTS"
445                     " (OBJECT_ID, PARENT_ID, REF_ID, DETAIL_ID, CLASS, NAME) "
446                     "VALUES"
447                     " ('%s%s$%X', '%s%s', %Q, %"PRId64", '%s', '%q')",
448                     base, parentID, objectID, base, parentID, refID, detailID, class, name);
449        if( refID )
450                free(refID);
451
452        return -1;
453}
454
455int
456insert_file(char * name, const char * path, const char * parentID, int object)
457{
458        char class[32];
459        char objectID[64];
460        sqlite3_int64 detailID = 0;
461        char base[8];
462        char * typedir_parentID;
463        int typedir_objectID;
464        char * baseid;
465        char * orig_name = NULL;
466
467        if( is_image(name) )
468        {
469                if( is_album_art(name) )
470                        return -1;
471                strcpy(base, IMAGE_DIR_ID);
472                strcpy(class, "item.imageItem.photo");
473                detailID = GetImageMetadata(path, name);
474        }
475        else if( is_video(name) )
476        {
477                orig_name = strdup(name);
478                strcpy(base, VIDEO_DIR_ID);
479                strcpy(class, "item.videoItem");
480                detailID = GetVideoMetadata(path, name);
481                if( !detailID )
482                        strcpy(name, orig_name);
483        }
484        else if( is_playlist(name) )
485        {
486                if( insert_playlist(path, name) == 0 )
487                        return 1;
488        }
489        if( !detailID && is_audio(name) )
490        {
491                strcpy(base, MUSIC_DIR_ID);
492                strcpy(class, "item.audioItem.musicTrack");
493                detailID = GetAudioMetadata(path, name);
494        }
495        if( orig_name )
496                free(orig_name);
497        if( !detailID )
498        {
499                DPRINTF(E_WARN, L_SCANNER, "Unsuccessful getting details for %s!\n", path);
500                return -1;
501        }
502
503        sprintf(objectID, "%s%s$%X", BROWSEDIR_ID, parentID, object);
504
505        sql_exec(db, "INSERT into OBJECTS"
506                     " (OBJECT_ID, PARENT_ID, CLASS, DETAIL_ID, NAME) "
507                     "VALUES"
508                     " ('%s', '%s%s', '%s', %"PRId64", '%q')",
509                     objectID, BROWSEDIR_ID, parentID, class, detailID, name);
510
511        if( *parentID )
512        {
513                typedir_objectID = 0;
514                typedir_parentID = strdup(parentID);
515                baseid = strrchr(typedir_parentID, '$');
516                if( baseid )
517                {
518                        typedir_objectID = strtol(baseid+1, NULL, 16);
519                        *baseid = '\0';
520                }
521                insert_directory(name, path, base, typedir_parentID, typedir_objectID);
522                free(typedir_parentID);
523        }
524        sql_exec(db, "INSERT into OBJECTS"
525                     " (OBJECT_ID, PARENT_ID, REF_ID, CLASS, DETAIL_ID, NAME) "
526                     "VALUES"
527                     " ('%s%s$%X', '%s%s', '%s', '%s', %"PRId64", '%q')",
528                     base, parentID, object, base, parentID, objectID, class, detailID, name);
529
530        insert_containers(name, path, objectID, class, detailID);
531        return 0;
532}
533
534int
535CreateDatabase(void)
536{
537        int ret, i;
538        const char * containers[] = { "0","-1",   "root",
539                                 MUSIC_ID, "0", _("Music"),
540                             MUSIC_ALL_ID, MUSIC_ID, _("All Music"),
541                           MUSIC_GENRE_ID, MUSIC_ID, _("Genre"),
542                          MUSIC_ARTIST_ID, MUSIC_ID, _("Artist"),
543                           MUSIC_ALBUM_ID, MUSIC_ID, _("Album"),
544                             MUSIC_DIR_ID, MUSIC_ID, _("Folders"),
545                           MUSIC_PLIST_ID, MUSIC_ID, _("Playlists"),
546
547                                 VIDEO_ID, "0", _("Video"),
548                             VIDEO_ALL_ID, VIDEO_ID, _("All Video"),
549                             VIDEO_DIR_ID, VIDEO_ID, _("Folders"),
550
551                                 IMAGE_ID, "0", _("Pictures"),
552                             IMAGE_ALL_ID, IMAGE_ID, _("All Pictures"),
553                            IMAGE_DATE_ID, IMAGE_ID, _("Date Taken"),
554                          IMAGE_CAMERA_ID, IMAGE_ID, _("Camera"),
555                             IMAGE_DIR_ID, IMAGE_ID, _("Folders"),
556
557                             BROWSEDIR_ID, "0", _("Browse Folders"),
558                        0 };
559
560        ret = sql_exec(db, "CREATE TABLE OBJECTS ( "
561                                        "ID INTEGER PRIMARY KEY AUTOINCREMENT, "
562                                        "OBJECT_ID TEXT UNIQUE NOT NULL, "
563                                        "PARENT_ID TEXT NOT NULL, "
564                                        "REF_ID TEXT DEFAULT NULL, "
565                                        "CLASS TEXT NOT NULL, "
566                                        "DETAIL_ID INTEGER DEFAULT NULL, "
567                                        "NAME TEXT DEFAULT NULL"
568                                        ");");
569        if( ret != SQLITE_OK )
570                goto sql_failed;
571        ret = sql_exec(db, "CREATE TABLE DETAILS ( "
572                                        "ID INTEGER PRIMARY KEY AUTOINCREMENT, "
573                                        "PATH TEXT DEFAULT NULL, "
574                                        "SIZE INTEGER, "
575                                        "TITLE TEXT COLLATE NOCASE, "
576                                        "DURATION TEXT, "
577                                        "BITRATE INTEGER, "
578                                        "SAMPLERATE INTEGER, "
579                                        "ARTIST TEXT COLLATE NOCASE, "
580                                        "ALBUM TEXT COLLATE NOCASE, "
581                                        "GENRE TEXT COLLATE NOCASE, "
582                                        "COMMENT TEXT, "
583                                        "CHANNELS INTEGER, "
584                                        "TRACK INTEGER, "
585                                        "DATE DATE, "
586                                        "RESOLUTION TEXT, "
587                                        "THUMBNAIL BOOL DEFAULT 0, "
588                                        "CREATOR TEXT COLLATE NOCASE, "
589                                        "DLNA_PN TEXT, "
590                                        "MIME TEXT, "
591                                        "ALBUM_ART INTEGER DEFAULT 0, "
592                                        "DISC INTEGER, "
593                                        "TIMESTAMP INTEGER"
594                                        ")");
595        if( ret != SQLITE_OK )
596                goto sql_failed;
597        ret = sql_exec(db, "CREATE TABLE ALBUM_ART ( "
598                                        "ID INTEGER PRIMARY KEY AUTOINCREMENT, "
599                                        "PATH TEXT NOT NULL"
600                                        ")");
601        if( ret != SQLITE_OK )
602                goto sql_failed;
603        ret = sql_exec(db, "CREATE TABLE CAPTIONS ("
604                                        "ID INTEGER PRIMARY KEY, "
605                                        "PATH TEXT NOT NULL"
606                                        ")");
607        if( ret != SQLITE_OK )
608                goto sql_failed;
609        ret = sql_exec(db, "CREATE TABLE BOOKMARKS ("
610                                        "ID INTEGER PRIMARY KEY, "
611                                        "SEC INTEGER"
612                                        ")");
613        if( ret != SQLITE_OK )
614                goto sql_failed;
615        ret = sql_exec(db, "CREATE TABLE PLAYLISTS ("
616                                        "ID INTEGER PRIMARY KEY AUTOINCREMENT, "
617                                        "NAME TEXT NOT NULL, "
618                                        "PATH TEXT NOT NULL, "
619                                        "ITEMS INTEGER DEFAULT 0, "
620                                        "FOUND INTEGER DEFAULT 0"
621                                        ")");
622        if( ret != SQLITE_OK )
623                goto sql_failed;
624        ret = sql_exec(db, "CREATE TABLE SETTINGS ("
625                                        "UPDATE_ID INTEGER PRIMARY KEY DEFAULT 0, "
626                                        "FLAGS INTEGER DEFAULT 0"
627                                        ")");
628        if( ret != SQLITE_OK )
629                goto sql_failed;
630        ret = sql_exec(db, "INSERT into SETTINGS values (0, 0)");
631        if( ret != SQLITE_OK )
632                goto sql_failed;
633        for( i=0; containers[i]; i=i+3 )
634        {
635                ret = sql_exec(db, "INSERT into OBJECTS (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME)"
636                                   " values "
637                                   "('%s', '%s', %lld, 'container.storageFolder', '%q')",
638                                   containers[i], containers[i+1], GetFolderMetadata(containers[i+2], NULL, NULL, NULL, 0), containers[i+2]);
639                if( ret != SQLITE_OK )
640                        goto sql_failed;
641        }
642        sql_exec(db, "create INDEX IDX_OBJECTS_OBJECT_ID ON OBJECTS(OBJECT_ID);");
643        sql_exec(db, "create INDEX IDX_OBJECTS_PARENT_ID ON OBJECTS(PARENT_ID);");
644        sql_exec(db, "create INDEX IDX_OBJECTS_DETAIL_ID ON OBJECTS(DETAIL_ID);");
645        sql_exec(db, "create INDEX IDX_OBJECTS_CLASS ON OBJECTS(CLASS);");
646        sql_exec(db, "create INDEX IDX_DETAILS_PATH ON DETAILS(PATH);");
647        sql_exec(db, "create INDEX IDX_DETAILS_ID ON DETAILS(ID);");
648        sql_exec(db, "create INDEX IDX_ALBUM_ART ON ALBUM_ART(ID);");
649        sql_exec(db, "create INDEX IDX_SCANNER_OPT ON OBJECTS(PARENT_ID, NAME, OBJECT_ID);");
650
651sql_failed:
652        if( ret != SQLITE_OK )
653                fprintf(stderr, "Error creating SQLite3 database!\n");
654        return (ret != SQLITE_OK);
655}
656
657int
658filter_audio(const struct dirent *d)
659{
660        return ( (*d->d_name != '.') &&
661                 ((d->d_type == DT_DIR) ||
662                  (d->d_type == DT_LNK) ||
663                  (d->d_type == DT_UNKNOWN) ||
664                  ((d->d_type == DT_REG) &&
665                   (is_audio(d->d_name) ||
666                    is_playlist(d->d_name)
667                   )
668               ) ));
669}
670
671int
672filter_video(const struct dirent *d)
673{
674        return ( (*d->d_name != '.') &&
675                 ((d->d_type == DT_DIR) ||
676                  (d->d_type == DT_LNK) ||
677                  (d->d_type == DT_UNKNOWN) ||
678                  ((d->d_type == DT_REG) &&
679                   is_video(d->d_name) )
680               ) );
681}
682
683int
684filter_images(const struct dirent *d)
685{
686        return ( (*d->d_name != '.') &&
687                 ((d->d_type == DT_DIR) ||
688                  (d->d_type == DT_LNK) ||
689                  (d->d_type == DT_UNKNOWN) ||
690                  ((d->d_type == DT_REG) &&
691                   is_image(d->d_name) )
692               ) );
693}
694
695int
696filter_media(const struct dirent *d)
697{
698        return ( (*d->d_name != '.') &&
699                 ((d->d_type == DT_DIR) ||
700                  (d->d_type == DT_LNK) ||
701                  (d->d_type == DT_UNKNOWN) ||
702                  ((d->d_type == DT_REG) &&
703                   (is_image(d->d_name) ||
704                    is_audio(d->d_name) ||
705                    is_video(d->d_name) ||
706                    is_playlist(d->d_name)
707                   )
708               ) ));
709}
710
711void
712ScanDirectory(const char * dir, const char * parent, enum media_types dir_type)
713{
714        struct dirent **namelist;
715        int i, n, startID=0;
716        char parent_id[PATH_MAX];
717        char full_path[PATH_MAX];
718        char * name = NULL;
719        static long long unsigned int fileno = 0;
720        enum file_types type;
721
722        setlocale(LC_COLLATE, "");
723        if( chdir(dir) != 0 )
724                return;
725
726        DPRINTF(parent?E_INFO:E_WARN, L_SCANNER, _("Scanning %s\n"), dir);
727        switch( dir_type )
728        {
729                case ALL_MEDIA:
730                        n = scandir(".", &namelist, filter_media, alphasort);
731                        break;
732                case AUDIO_ONLY:
733                        n = scandir(".", &namelist, filter_audio, alphasort);
734                        break;
735                case VIDEO_ONLY:
736                        n = scandir(".", &namelist, filter_video, alphasort);
737                        break;
738                case IMAGES_ONLY:
739                        n = scandir(".", &namelist, filter_images, alphasort);
740                        break;
741                default:
742                        n = -1;
743                        break;
744        }
745        if (n < 0) {
746                fprintf(stderr, "Error scanning %s [scandir]\n", dir);
747                return;
748        }
749
750        if( !parent )
751        {
752                startID = get_next_available_id("OBJECTS", BROWSEDIR_ID);
753        }
754
755        for (i=0; i < n; i++)
756        {
757#if !USE_FORK
758                if( quitting )
759                        break;
760#endif
761                type = TYPE_UNKNOWN;
762                sprintf(full_path, "%s/%s", dir, namelist[i]->d_name);
763                name = escape_tag(namelist[i]->d_name, 1);
764                if( namelist[i]->d_type == DT_DIR )
765                {
766                        type = TYPE_DIR;
767                }
768                else if( namelist[i]->d_type == DT_REG )
769                {
770                        type = TYPE_FILE;
771                }
772                else
773                {
774                        type = resolve_unknown_type(full_path, dir_type);
775                }
776                if( (type == TYPE_DIR) && (access(full_path, R_OK|X_OK) == 0) )
777                {
778                        insert_directory(name, full_path, BROWSEDIR_ID, (parent ? parent:""), i+startID);
779                        sprintf(parent_id, "%s$%X", (parent ? parent:""), i+startID);
780                        ScanDirectory(full_path, parent_id, dir_type);
781                }
782                else if( type == TYPE_FILE && (access(full_path, R_OK) == 0) )
783                {
784                        if( insert_file(name, full_path, (parent ? parent:""), i+startID) == 0 )
785                                fileno++;
786                }
787                free(name);
788                free(namelist[i]);
789        }
790        free(namelist);
791        if( parent )
792        {
793                chdir(dirname((char*)dir));
794        }
795        else
796        {
797                DPRINTF(E_WARN, L_SCANNER, _("Scanning %s finished (%llu files)!\n"), dir, fileno);
798        }
799}
800
801void
802start_scanner()
803{
804        struct media_dir_s * media_path = media_dirs;
805
806        if (setpriority(PRIO_PROCESS, 0, 15) == -1)
807                DPRINTF(E_WARN, L_INOTIFY,  "Failed to reduce scanner thread priority\n");
808
809#ifdef READYNAS
810        FILE * flag = fopen("/ramfs/.upnp-av_scan", "w");
811        if( flag )
812                fclose(flag);
813#endif
814        freopen("/dev/null", "a", stderr);
815        while( media_path )
816        {
817                ScanDirectory(media_path->path, NULL, media_path->type);
818                media_path = media_path->next;
819        }
820        freopen("/proc/self/fd/2", "a", stderr);
821#ifdef READYNAS
822        if( access("/ramfs/.rescan_done", F_OK) == 0 )
823                system("/bin/sh /ramfs/.rescan_done");
824        unlink("/ramfs/.upnp-av_scan");
825#endif
826        /* Create this index after scanning, so it doesn't slow down the scanning process.
827         * This index is very useful for large libraries used with an XBox360 (or any
828         * client that uses UPnPSearch on large containers). */
829        sql_exec(db, "create INDEX IDX_SEARCH_OPT ON OBJECTS(OBJECT_ID, CLASS, DETAIL_ID);");
830
831        fill_playlists();
832
833        //JM: Set up a db version number, so we know if we need to rebuild due to a new structure.
834        sql_exec(db, "pragma user_version = %d;", DB_VERSION);
835}
Note: See TracBrowser for help on using the repository browser.