int insert_playlist(const char * path, char * name) { struct song_metadata plist; struct stat file; int items = 0, matches, ret; char type[4]; strncpy(type, strrchr(name, '.')+1, 4); if( start_plist(path, NULL, &file, NULL, type) != 0 ) { DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path); return -1; } while( (ret = next_plist_track(&plist, &file, NULL, type)) == 0 ) { items++; freetags(&plist); } if( ret == 2 ) // Bad playlist -- contains binary characters { DPRINTF(E_WARN, L_SCANNER, "Bad playlist [%s]\n", path); return -1; } strip_ext(name); DPRINTF(E_DEBUG, L_SCANNER, "Playlist %s contains %d items\n", name, items); matches = sql_get_int_field(db, "SELECT count(*) from PLAYLISTS where NAME = '%q'", name); if( matches > 0 ) { sql_exec(db, "INSERT into PLAYLISTS" " (NAME, PATH, ITEMS) " "VALUES" " ('%q(%d)', '%q', %d)", name, matches, path, items); } else { sql_exec(db, "INSERT into PLAYLISTS" " (NAME, PATH, ITEMS) " "VALUES" " ('%q', '%q', %d)", name, path, items); } sql_exec(db, "INSERT into DETAILS" " (PATH, TIMESTAMP, MIME) " "VALUES" " ('%q', %ld, 'audio/x-mpegurl')", path, 0); return 0; }
struct file_tags *gettags(int sock) { struct file_tags *tags = newtags(); if(!((tags->title = getstring(sock)) && (tags->artist = getstring(sock)) && (tags->album = getstring(sock)))) { dbg_log(ERR_ERR, "No title/artist/album received."); freetags(tags); return NULL; } getint(sock, &tags->track); getint(sock, &tags->time); getint(sock, &tags->filled); return tags; }
int fill_playlists() { int rows, i, found, len; char **result; char *plpath, *plname, *fname; char class[] = "playlistContainer"; struct song_metadata plist; struct stat file; char type[4]; sqlite_int64 plID, detailID; char sql_buf[1024] = "SELECT ID, NAME, PATH from PLAYLISTS where ITEMS > FOUND"; if( sql_get_table(db, sql_buf, &result, &rows, NULL) != SQLITE_OK ) return -1; if( !rows ) { sqlite3_free_table(result); return 0; } rows++; for( i=3; i<rows*3; i++ ) { plID = strtoll(result[i], NULL, 10); plname = result[++i]; plpath = result[++i]; strncpy(type, strrchr(plpath, '.')+1, 4); if( start_plist(plpath, NULL, &file, NULL, type) != 0 ) continue; DPRINTF(E_DEBUG, L_SCANNER, "Scanning playlist \"%s\" [%s]\n", plname, plpath); if( sql_get_int_field(db, "SELECT ID from OBJECTS where PARENT_ID = '"MUSIC_PLIST_ID"'" " and NAME = '%q'", plname) <= 0 ) { detailID = GetFolderMetadata(plname, NULL, NULL, NULL, NULL); sql_exec(db, "INSERT into OBJECTS" " (OBJECT_ID, PARENT_ID, DETAIL_ID, CLASS, NAME) " "VALUES" " ('%s$%llX', '%s', %lld, 'container.%s', '%q')", MUSIC_PLIST_ID, plID, MUSIC_PLIST_ID, detailID, class, plname); } plpath = dirname(plpath); found = 0; while( next_plist_track(&plist, &file, NULL, type) == 0 ) { if( sql_get_int_field(db, "SELECT 1 from OBJECTS where OBJECT_ID = '%s$%llX$%d'", MUSIC_PLIST_ID, plID, plist.track) == 1 ) { //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "%d: already in database\n", plist.track); found++; freetags(&plist); continue; } fname = plist.path; DPRINTF(E_DEBUG, L_SCANNER, "%d: checking database for %s\n", plist.track, plist.path); if( !strpbrk(fname, "\\/") ) { len = strlen(fname) + strlen(plpath) + 2; plist.path = malloc(len); snprintf(plist.path, len, "%s/%s", plpath, fname); free(fname); fname = plist.path; } else { while( *fname == '\\' ) { fname++; } } retry: //DEBUG DPRINTF(E_DEBUG, L_SCANNER, "* Searching for %s in db\n", fname); detailID = sql_get_int_field(db, "SELECT ID from DETAILS where PATH like '%%%q'", fname); if( detailID > 0 ) { DPRINTF(E_DEBUG, L_SCANNER, "+ %s found in db\n", fname); sql_exec(db, "INSERT into OBJECTS" " (OBJECT_ID, PARENT_ID, CLASS, DETAIL_ID, NAME, REF_ID) " "SELECT" " '%s$%llX$%d', '%s$%llX', CLASS, DETAIL_ID, NAME, OBJECT_ID from OBJECTS" " where DETAIL_ID = %lld and OBJECT_ID glob '" BROWSEDIR_ID "$*'", MUSIC_PLIST_ID, plID, plist.track, MUSIC_PLIST_ID, plID, detailID); found++; } else { DPRINTF(E_DEBUG, L_SCANNER, "- %s not found in db\n", fname); if( strchr(fname, '\\') ) { fname = modifyString(fname, "\\", "/", 0); goto retry; } else if( (fname = strchr(fname, '/')) ) { fname++; goto retry; } } freetags(&plist); } sql_exec(db, "UPDATE PLAYLISTS set FOUND = %d where ID = %lld", found, plID); }
int64_t GetAudioMetadata(const char *path, char *name) { char type[4]; static char lang[6] = { '\0' }; struct stat file; int64_t ret; char *esc_tag; int i; int64_t album_art = 0; struct song_metadata song; metadata_t m; uint32_t free_flags = FLAG_MIME|FLAG_DURATION|FLAG_DLNA_PN|FLAG_DATE; memset(&m, '\0', sizeof(metadata_t)); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); if( ends_with(path, ".mp3") ) { strcpy(type, "mp3"); m.mime = strdup("audio/mpeg"); } else if( ends_with(path, ".m4a") || ends_with(path, ".mp4") || ends_with(path, ".aac") || ends_with(path, ".m4p") ) { strcpy(type, "aac"); m.mime = strdup("audio/mp4"); } else if( ends_with(path, ".3gp") ) { strcpy(type, "aac"); m.mime = strdup("audio/3gpp"); } else if( ends_with(path, ".wma") || ends_with(path, ".asf") ) { strcpy(type, "asf"); m.mime = strdup("audio/x-ms-wma"); } else if( ends_with(path, ".flac") || ends_with(path, ".fla") || ends_with(path, ".flc") ) { strcpy(type, "flc"); m.mime = strdup("audio/x-flac"); } else if( ends_with(path, ".wav") ) { strcpy(type, "wav"); m.mime = strdup("audio/x-wav"); } else if( ends_with(path, ".ogg") || ends_with(path, ".oga") ) { strcpy(type, "ogg"); m.mime = strdup("audio/ogg"); } else if( ends_with(path, ".pcm") ) { strcpy(type, "pcm"); m.mime = strdup("audio/L16"); } else { DPRINTF(E_WARN, L_GENERAL, "Unhandled file extension on %s\n", path); return 0; } if( !(*lang) ) { if( !getenv("LANG") ) strcpy(lang, "en_US"); else strncpyt(lang, getenv("LANG"), sizeof(lang)); } if( readtags((char *)path, &song, &file, lang, type) != 0 ) { DPRINTF(E_WARN, L_GENERAL, "Cannot extract tags from %s!\n", path); freetags(&song); free_metadata(&m, free_flags); return 0; } if( song.dlna_pn ) m.dlna_pn = strdup(song.dlna_pn); if( song.year ) xasprintf(&m.date, "%04d-01-01", song.year); xasprintf(&m.duration, "%d:%02d:%02d.%03d", (song.song_length/3600000), (song.song_length/60000%60), (song.song_length/1000%60), (song.song_length%1000)); if( song.title && *song.title ) { m.title = trim(song.title); if( (esc_tag = escape_tag(m.title, 0)) ) { free_flags |= FLAG_TITLE; m.title = esc_tag; } } else { m.title = name; } for( i=ROLE_START; i<N_ROLE; i++ ) { if( song.contributor[i] && *song.contributor[i] ) { m.creator = trim(song.contributor[i]); if( strlen(m.creator) > 48 ) { m.creator = strdup("Various Artists"); free_flags |= FLAG_CREATOR; } else if( (esc_tag = escape_tag(m.creator, 0)) ) { m.creator = esc_tag; free_flags |= FLAG_CREATOR; } m.artist = m.creator; break; } } /* If there is a band associated with the album, use it for virtual containers. */ if( (i != ROLE_BAND) && (i != ROLE_ALBUMARTIST) ) { if( song.contributor[ROLE_BAND] && *song.contributor[ROLE_BAND] ) { i = ROLE_BAND; m.artist = trim(song.contributor[i]); if( strlen(m.artist) > 48 ) { m.artist = strdup("Various Artists"); free_flags |= FLAG_ARTIST; } else if( (esc_tag = escape_tag(m.artist, 0)) ) { m.artist = esc_tag; free_flags |= FLAG_ARTIST; } } } if( song.album && *song.album ) { m.album = trim(song.album); if( (esc_tag = escape_tag(m.album, 0)) ) { free_flags |= FLAG_ALBUM; m.album = esc_tag; } } if( song.genre && *song.genre ) { m.genre = trim(song.genre); if( (esc_tag = escape_tag(m.genre, 0)) ) { free_flags |= FLAG_GENRE; m.genre = esc_tag; } } if( song.comment && *song.comment ) { m.comment = trim(song.comment); if( (esc_tag = escape_tag(m.comment, 0)) ) { free_flags |= FLAG_COMMENT; m.comment = esc_tag; } } album_art = find_album_art(path, song.image, song.image_size); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, SIZE, TIMESTAMP, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE," " TITLE, CREATOR, ARTIST, ALBUM, GENRE, COMMENT, DISC, TRACK, DLNA_PN, MIME, ALBUM_ART) " "VALUES" " (%Q, %lld, %ld, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d, %d, %Q, '%s', %lld);", path, (long long)file.st_size, file.st_mtime, m.duration, song.channels, song.bitrate, song.samplerate, m.date, m.title, m.creator, m.artist, m.album, m.genre, m.comment, song.disc, song.track, m.dlna_pn, song.mime?song.mime:m.mime, album_art); if( ret != SQLITE_OK ) { fprintf(stderr, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } freetags(&song); free_metadata(&m, free_flags); return ret; }
int64_t GetAudioMetadata(const char *path, char *name) { char type[4]; static char lang[6] = { '\0' }; struct stat file; int64_t ret; char *esc_tag; int i; int64_t album_art = 0; struct song_metadata song; metadata_t m; uint32_t free_flags = FLAG_MIME|FLAG_DURATION|FLAG_DLNA_PN|FLAG_DATE; memset(&m, '\0', sizeof(metadata_t)); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); if( ends_with(path, ".mp3") ) { strcpy(type, "mp3"); m.mime = strdup("audio/mpeg"); } else if( ends_with(path, ".m4a") || ends_with(path, ".mp4") || ends_with(path, ".aac") || ends_with(path, ".m4p") ) { strcpy(type, "aac"); m.mime = strdup("audio/mp4"); } else if( ends_with(path, ".3gp") ) { strcpy(type, "aac"); m.mime = strdup("audio/3gpp"); } else if( ends_with(path, ".wma") || ends_with(path, ".asf") ) { strcpy(type, "asf"); m.mime = strdup("audio/x-ms-wma"); } else if( ends_with(path, ".flac") || ends_with(path, ".fla") || ends_with(path, ".flc") ) { strcpy(type, "flc"); m.mime = strdup("audio/x-flac"); } else if( ends_with(path, ".wav") ) { strcpy(type, "wav"); m.mime = strdup("audio/x-wav"); } else if( ends_with(path,".oga") || ends_with(path,".ogg")) { /* The .ogg/.oga file extensions present something of a problem. * ".ogg" has been deprecated in favor of ".oga" for some time, but * many applications still only recognize ".ogg". * * This examines the file and causes .ogg to be presented for any naked * Vorbis file (MIME type audio/ogg; codecs=vorbis) and .oga * (audio/ogg) to be used for everything else. This is in line with * the official ogg naming conventions and, hopefully, makes for a * resonable compromise. */ uint8_t oggtestbuf[35]; FILE *oggfile = fopen (path, "rb"); if (oggfile == (FILE *)NULL) { DPRINTF(E_ERROR, L_METADATA, "Error opening %s\n", path); return 0; } if (fread (oggtestbuf, 1, 35, oggfile) != 35) { DPRINTF(E_WARN, L_METADATA, "Premature EOF on %s\n", path); fclose (oggfile); return 0; } fclose (oggfile); if (memcmp (&oggtestbuf[28], "\x01vorbis", 7)) m.mime = strdup ("audio/ogg"); else m.mime = strdup ("audio/ogg; codecs=vorbis"); strcpy(type, "ogg"); } else if ( ends_with(path, ".opus") ) { strcpy(type,"ops"); m.mime = strdup("audio/ogg; codecs=opus"); } #if 0 /* Not supported yet, and probably won't be. */ else if( ends_with(path, ".ogx") ) { strcpy(type, "ogx"); m.mime = strdup("application/ogg"); } #endif else if( ends_with(path, ".pcm") ) { strcpy(type, "pcm"); m.mime = strdup("audio/L16"); } else { DPRINTF(E_WARN, L_METADATA, "Unhandled file extension on %s\n", path); return 0; } if( !(*lang) ) { if( !getenv("LANG") ) strcpy(lang, "en_US"); else strncpyt(lang, getenv("LANG"), sizeof(lang)); } if( readtags((char *)path, &song, &file, lang, type) != 0 ) { DPRINTF(E_WARN, L_METADATA, "Cannot extract tags from %s!\n", path); freetags(&song); free_metadata(&m, free_flags); return 0; } if( song.dlna_pn ) m.dlna_pn = strdup(song.dlna_pn); if( song.year ) xasprintf(&m.date, "%04d-01-01", song.year); xasprintf(&m.duration, "%d:%02d:%02d.%03d", (song.song_length/3600000), (song.song_length/60000%60), (song.song_length/1000%60), (song.song_length%1000)); if( song.title && *song.title ) { m.title = trim(song.title); if( (esc_tag = escape_tag(m.title, 0)) ) { free_flags |= FLAG_TITLE; m.title = esc_tag; } } else { m.title = name; } for( i = ROLE_START; i < N_ROLE; i++ ) { if( song.contributor[i] && *song.contributor[i] ) { m.creator = trim(song.contributor[i]); if( strlen(m.creator) > 48 ) { m.creator = strdup("Various Artists"); free_flags |= FLAG_CREATOR; } else if( (esc_tag = escape_tag(m.creator, 0)) ) { m.creator = esc_tag; free_flags |= FLAG_CREATOR; } m.artist = m.creator; break; } } /* If there is a album artist or band associated with the album, use it for virtual containers. */ if( i < ROLE_ALBUMARTIST ) { for( i = ROLE_ALBUMARTIST; i <= ROLE_BAND; i++ ) { if( song.contributor[i] && *song.contributor[i] ) break; } if( i <= ROLE_BAND ) { m.artist = trim(song.contributor[i]); if( strlen(m.artist) > 48 ) { m.artist = strdup("Various Artists"); free_flags |= FLAG_ARTIST; } else if( (esc_tag = escape_tag(m.artist, 0)) ) { m.artist = esc_tag; free_flags |= FLAG_ARTIST; } } } if( song.album && *song.album ) { m.album = trim(song.album); if( (esc_tag = escape_tag(m.album, 0)) ) { free_flags |= FLAG_ALBUM; m.album = esc_tag; } } if( song.genre && *song.genre ) { m.genre = trim(song.genre); if( (esc_tag = escape_tag(m.genre, 0)) ) { free_flags |= FLAG_GENRE; m.genre = esc_tag; } } if( song.comment && *song.comment ) { m.comment = trim(song.comment); if( (esc_tag = escape_tag(m.comment, 0)) ) { free_flags |= FLAG_COMMENT; m.comment = esc_tag; } } album_art = find_album_art(path, song.image, song.image_size); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, SIZE, TIMESTAMP, DURATION, CHANNELS, BITRATE, SAMPLERATE, DATE," " TITLE, CREATOR, ARTIST, ALBUM, GENRE, COMMENT, DISC, TRACK, DLNA_PN, MIME, ALBUM_ART) " "VALUES" " (%Q, %lld, %lld, '%s', %d, %d, %d, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %d, %d, %Q, '%s', %lld);", path, (long long)file.st_size, (long long)file.st_mtime, m.duration, song.channels, song.bitrate, song.samplerate, m.date, m.title, m.creator, m.artist, m.album, m.genre, m.comment, song.disc, song.track, m.dlna_pn, song.mime?song.mime:m.mime, album_art); if( ret != SQLITE_OK ) { DPRINTF(E_ERROR, L_METADATA, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } freetags(&song); free_metadata(&m, free_flags); return ret; }