package org.lysty.core; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.lysty.dao.Song; import org.lysty.db.DBHandler; import org.lysty.exceptions.FeatureExtractionException; import org.lysty.extractors.ExtractSequencer; public class SongIndexer { public static final int DEFAULT_DEPTHS_TO_INDEX = 100; // update notification precision. 100 means every 1% completion is notified. private static final int INDEX_UPDATE_PERCENTAGE = 100; static String[] exts = null; static FileFilter filter = new FileFilter() { @Override public boolean accept(File file) { if (file.getName() == null) return false; if (file.isDirectory()) return true; for (String ext : exts) { if (file.getName().toLowerCase().endsWith("." + ext)) return true; } return false; } }; public static Map<String, Long> folderIndexMap = new HashMap<String, Long>(); public static Map<String, Long> extractorTimestampMap = new HashMap<String, Long>(); public static List<Song> songList = new ArrayList<Song>(); // song list to // index static File[] list; // temp var to hold file filter results; private static List<Song> allSongs; private static File currentIndexingFolder = null; private static Long maxExtractorTimstamp; private static boolean isCancelled; private static void createFolderIndexMap() { folderIndexMap = DBHandler.getInstance().getFolderIndexMap(); extractorTimestampMap = DBHandler.getInstance() .getExtractorTimestampMap(); Iterator<Long> it = extractorTimestampMap.values().iterator(); maxExtractorTimstamp = 0l; while (it.hasNext()) { maxExtractorTimstamp = Math.max(maxExtractorTimstamp, it.next()); } } private static void createFileList(File folder, int depths, boolean isIncremental) { list = folder.listFiles(filter); long id; if (list == null) return; Song song = null; Long lastIndex; for (File file : list) { if (file.isDirectory() && depths > 0) { createFileList(file, depths - 1, isIncremental); } else { lastIndex = folderIndexMap.get(folder.getPath()); int songInDBIndex = allSongs.indexOf(new Song(file)); if (songInDBIndex >= 0) song = allSongs.get(songInDBIndex); if (!isIncremental || (lastIndex == null || songInDBIndex == -1 || maxExtractorTimstamp > lastIndex)) { if (songInDBIndex == -1) { song = new Song(); song.setFile(file); song.setName(file.getName()); id = DBHandler.getInstance().insertSong(song); song.setId(id); } songList.add(song); } } } } private static void extractFeatures(Song song) throws FeatureExtractionException { File parentFolder = song.getFile().getParentFile(); if (currentIndexingFolder == null) { currentIndexingFolder = parentFolder; } else if (!currentIndexingFolder.equals(parentFolder)) { // done with current indexing folder. DBHandler.getInstance().setFolderIndexTimestamp( currentIndexingFolder, System.currentTimeMillis()); currentIndexingFolder = parentFolder; } ExtractSequencer.getInstance().extract(song, folderIndexMap.get(parentFolder.getPath())); DBHandler.getInstance().insertAttributes(song); } public static void index(File[] folders, int depths, boolean isIncremental, UpdateListener updater) { init(); createFolderIndexMap(); allSongs = DBHandler.getInstance().getSongs(null); for (File folder : folders) { createFileList(folder, depths, isIncremental); } updater.setSize(songList.size()); runExtractor(updater); } private static void init() { // TODO Auto-generated method stub isCancelled = false; songList = new ArrayList<Song>(); currentIndexingFolder = null; exts = ExtractorManager.getSupportedFormats(); } /** * Runs the extractor * * @param updater * updater to notify of progress of run * @return the files that failed during extraction */ private static List<Song> runExtractor(UpdateListener updater) { List<Song> failedList = new ArrayList<Song>(); int indexUpdateChunk = (songList.size() / INDEX_UPDATE_PERCENTAGE) + 1; int success = 0; for (int i = 0; i < songList.size(); i++) { try { if (isCancelled) return null; extractFeatures(songList.get(i)); success++; } catch (FeatureExtractionException e) { failedList.add(songList.get(i)); updater.notifyError(e); } if (i % indexUpdateChunk == 0) { updater.notifyUpdate(i, "Indexing: " + songList.get(i).getFile().getParent()); updater.notifyCurrentSuccessCount(success); } } if (!songList.isEmpty()) { // update the last folder indexed's timestamp currentIndexingFolder = songList.get(songList.size() - 1).getFile() .getParentFile(); DBHandler.getInstance().setFolderIndexTimestamp( currentIndexingFolder, System.currentTimeMillis()); } updater.notifyComplete(); return failedList; } public static void cancel() { isCancelled = true; } }