/**
*
* TURTLE PLAYER
*
* Licensed under MIT & GPL
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
* OR OTHER DEALINGS IN THE SOFTWARE.
*
* More Information @ www.turtle-player.co.uk
*
* @author Simon Honegger (Hoene84)
*/
package com.turtleplayer.persistance.turtle;
import android.util.Log;
import com.mpatric.mp3agic.ID3v1;
import com.mpatric.mp3agic.InvalidDataException;
import com.mpatric.mp3agic.Mp3File;
import com.mpatric.mp3agic.UnsupportedTagException;
import com.turtleplayer.common.filefilter.FileFilters;
import com.turtleplayer.model.*;
import com.turtleplayer.persistance.framework.executor.OperationExecutor;
import com.turtleplayer.persistance.framework.filter.FieldFilter;
import com.turtleplayer.persistance.framework.filter.Operator;
import com.turtleplayer.persistance.source.sql.First;
import com.turtleplayer.persistance.source.sqlite.QuerySqlite;
import com.turtleplayer.persistance.turtle.db.TurtleDatabase;
import com.turtleplayer.persistance.turtle.db.structure.Tables;
import com.turtleplayer.persistance.turtle.mapping.AlbumArtLocationCreator;
import com.turtleplayer.preferences.Preferences;
import com.turtleplayer.util.Shorty;
import java.io.*;
import java.util.*;
public class FsReader
{
public static boolean scanFile(String filePath,
TurtleDatabase db,
Set<String> encounteredRootSrcs) throws IOException
{
// http://www.exampledepot.com/egs/java.io/GetFiles.html
Log.i(Preferences.TAG, "register " + filePath);
long start = System.currentTimeMillis();
String rootSrc = filePath.substring(0, filePath.lastIndexOf("/"));
String title = null;
String artist = null;
String album = null;
int genre = -1;
int number = 0;
try
{
synchronized (Mp3File.class)
{
Mp3File mp3file = new Mp3File(filePath, false);
final ID3v1 id3tag;
if(mp3file.hasId3v1Tag()){
id3tag = mp3file.getId3v1Tag();
}
else if(mp3file.hasId3v2Tag())
{
id3tag = mp3file.getId3v2Tag();
}
else
{
id3tag = null;
}
if(id3tag != null){
title = id3tag.getTitle();
artist = id3tag.getArtist();
album = id3tag.getAlbum();
genre = id3tag.getGenre();
number = parseTrackNumber(id3tag.getTrack());
}
}
}
catch (UnsupportedTagException e)
{
throw new IOException("Unable to read ID3 tag", e);
}
catch (InvalidDataException e)
{
throw new IOException("Unable to read ID3 tag", e);
}
if (Shorty.isVoid(title))
{
title = "Unknown";
}
if (Shorty.isVoid(album))
{
number = 0; //tracknumbers with no album results in strange sorting
}
Track t = new Track(
new SongDigest(title),
new ArtistDigest(artist),
new AlbumDigest(album),
new GenreDigest(genre < 0 ? "" : String.valueOf(genre)),
number,
filePath
);
Log.v(Preferences.TAG, "created " + (System.currentTimeMillis() - start) + "ms");
boolean added = db.push(t);
Log.v(Preferences.TAG, "pushed " + (System.currentTimeMillis() - start) + "ms");
if(added)
{
for(String parantPath = rootSrc; parantPath.lastIndexOf("/") >= 0; parantPath = parantPath.substring(0, parantPath.lastIndexOf("/")))
{
if(encounteredRootSrcs.add(parantPath))
{
db.push(new FSobject(parantPath));
}
}
}
return added;
}
static public List<String> getMediaFilesPaths(String mediaPath, List<? extends FilenameFilter> filters, boolean recursive, boolean getFirstMatch){
List<String> candidates = new ArrayList<String>();
try
{
String[] arguments = recursive ? new String[]{"ls", "-R", mediaPath} : new String[]{"ls", mediaPath};
Process p = Runtime.getRuntime().exec(arguments);
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String currPath = mediaPath + "/";
String line = "";
while (line != null)
{
line = br.readLine();
if (line != null)
{
if(line.startsWith("/")){
currPath = line;
currPath = currPath.lastIndexOf(":") == currPath.length()-1 ? currPath.substring(0, currPath.length()-1) : currPath;
currPath = currPath.indexOf(".") == 0 ? currPath.replaceFirst(".", mediaPath) : currPath;
currPath = currPath.lastIndexOf("/") != currPath.length()-1 ? currPath + "/" : currPath;
}
else
{
if(!Shorty.isVoid(line))
{
candidates.add(currPath + line);
}
}
}
}
} catch (IOException e)
{
//Empty
}
//Log.v(Preferences.TAG, "found " + candidates.size() + " "+ (System.currentTimeMillis() - start) + "ms");
List<String> acceptedPaths = new ArrayList<String>();
for (FilenameFilter filenameFilter : filters)
{
for(String path : candidates)
{
//Log.v(Preferences.TAG, "filter " + path + (System.currentTimeMillis() - start) + "ms " + path);
if(filenameFilter.accept(null, path)){
acceptedPaths.add(path);
if(getFirstMatch){
//Log.v(Preferences.TAG, "completed " + (System.currentTimeMillis() - start) + "ms " + path);
return acceptedPaths;
}
}
}
}
return acceptedPaths;
}
public static String getAlbumArt(String mediaFileDir, TurtleDatabase db)
{
final String result;
AlbumArtLocation albumArtLocation = OperationExecutor.execute(
db,
new QuerySqlite<Tables.AlbumArtLocations, Tables.AlbumArtLocations, AlbumArtLocation>(
new FieldFilter<Tables.AlbumArtLocations, AlbumArtLocation, String>(Tables.AlbumArtLocations.PATH, Operator.EQ, mediaFileDir),
new First<AlbumArtLocation>(Tables.ALBUM_ART_LOCATIONS, new AlbumArtLocationCreator())
)
);
if(albumArtLocation != null)
{
return albumArtLocation.getAlbumArtpath();
}
if (!Shorty.isVoid(mediaFileDir.replaceAll("/", "").replaceAll("\\.", ""))){
List<String> albumArtStrings = FsReader.getMediaFilesPaths(mediaFileDir, FileFilters.folderArtFilters, false, true);
if(!albumArtStrings.isEmpty())
{
result = albumArtStrings.iterator().next();
}
else
{
result = getAlbumArt(mediaFileDir.substring(0, mediaFileDir.lastIndexOf("/")), db);
}
}
else{
result = null;
}
db.push(new AlbumArtLocation(mediaFileDir, result));
return result;
}
static int parseTrackNumber(String trackNumber)
{
//strips all chars beginning at first non digit (e.g. 5/10)
String strippedTrackNumber = trackNumber == null ? "" : trackNumber.replaceAll("\\D.*", "");
if (strippedTrackNumber.length() > 0)
{
try
{
return Integer.parseInt(strippedTrackNumber);
}
catch (NumberFormatException e)
{
Log.w(Preferences.TAG, "Unable to parse track number :" + strippedTrackNumber);
}
}
return 0;
}
static double parseDuration(String duration)
{
try
{
return Double.parseDouble(duration);
} catch (NumberFormatException e)
{
Log.v(Preferences.TAG, "Unable to parse duration '" + duration + "': " + e.getMessage());
}
return 0;
}
final static FileFilter isDIR = new FileFilter()
{
final String[] IGNORED_DIRS = new String[]{
"/proc/",
"/sys/",
"/system/",
"/proc/",
"/root/",
};
public boolean accept(File file)
{
for (String ignoredDir : IGNORED_DIRS)
{
if(file.toString().startsWith(ignoredDir)){
return false;
}
}
return file.canRead() && file.isDirectory();
}
};
}