package net.kirke.mp3dj;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.kirke.mp3dj.resources.Msgs;
import net.kirke.mp3dj.resources.Props;
public class ApplicationService {
private int totalFolders;
private int totalGenres;
private int totalSeconds;
private Msgs msgs;
private Refresh refresh;
private String message = null;
private final char LINEFEED = 10;
private Thread thread = null;
private static String mp3Dir = Props.getProperty("mp3.dir");
private static String appVersion = Props.getProperty("app.version");
private static String playlistsDir = Props.getProperty("mp3.dir")
+ File.separator + Props.getProperty("playlists.subdir");
// constructors
public ApplicationService() {
totalGenres = 0;
totalSeconds = 0;
totalFolders = 0;
msgs = new Msgs();
System.out.println("ApplicationService: Starting mp3dj-" + appVersion + ".");
refresh = new Refresh();
refreshDatabase();
}
private void refreshDatabase() {
if ((thread == null) || !thread.isAlive()) {
thread = new Thread(refresh);
thread.setDaemon(true);
System.out.println("refreshDatabase: Starting Refresh() daemon thread.");
thread.start();
}
}
public Map putFileData(ResultSet rs) {
Map file;
try {
file = new HashMap();
file.put("id", rs.getInt("id"));
file.put("folder", rs.getString("folder"));
file.put("name", rs.getString("name"));
file.put("album", rs.getString("album"));
file.put("duration", rs.getString("duration"));
file.put("bitrate", rs.getInt("bitrate"));
file.put("kilobytes", rs.getInt("kilobytes"));
file.put("track", rs.getString("track"));
file.put("year", rs.getString("year"));
file.put("modified", rs.getString("modified"));
file.put("artist", rs.getString("artist"));
file.put("title", rs.getString("title"));
file.put("comment", rs.getString("comment"));
file.put("milliseconds", rs.getInt("milliseconds"));
file.put("messages", rs.getString("messages"));
file.put("genre", rs.getString("genre"));
} catch (SQLException x) {
x.printStackTrace();
throw new DAOException(x);
}
return file;
}
public synchronized List assembleFileData(String sql) throws DAOException {
ArrayList data = new ArrayList();
Connection connection = null;
try {
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
System.out.println("assembleFileData: sql=" + sql);
ResultSet rs = statement.executeQuery(sql);
Map file;
totalSeconds = 0;
while (rs.next()) {
file = putFileData(rs);
data.add(file);
totalSeconds += rs.getInt("milliseconds")/1000;
}
}
catch (SQLException x) {
x.printStackTrace();
throw new DAOException(x);
}
finally {
ConnectionHelper.close(connection);
}
return data;
}
public synchronized List assembleFolderData(String sql) throws DAOException {
ArrayList data = new ArrayList();
Connection connection = null;
try {
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
System.out.println("assembleFolderData: sql=" + sql);
ResultSet rs = statement.executeQuery(sql);
Map folder;
while (rs.next()) {
folder = new HashMap();
folder.put("label", rs.getString("folder"));
folder.put("dataTip", rs.getInt("files"));
folder.put("type", "folder");
data.add(folder);
}
}
catch (SQLException x) {
x.printStackTrace();
throw new DAOException(x);
}
finally {
ConnectionHelper.close(connection);
}
return data;
}
public synchronized List assembleGenreData(String sql) throws DAOException {
ArrayList data = new ArrayList();
Connection connection = null;
try {
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
System.out.println("assembleGenreData: sql=" + sql);
ResultSet rs = statement.executeQuery(sql);
Map genre;
while (rs.next()) {
genre = new HashMap();
genre.put("label", rs.getString("genre"));
genre.put("dataTip", rs.getString("files"));
genre.put("type", "genre");
data.add(genre);
}
}
catch (SQLException x) {
x.printStackTrace();
throw new DAOException(x);
}
finally {
ConnectionHelper.close(connection);
}
return data;
}
/**
* Compile list of filenames in mp3.dir/playlists.subdir.
* @return Value reference pointing to array list.
*/
public synchronized List assemblePlaylistData() {
ArrayList data = new ArrayList();
File playlistsFile = new File(playlistsDir);
if (playlistsFile.exists()) {
if (playlistsFile.isDirectory()) {
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".m3u");
}
};
String[] files = playlistsFile.list(filter);
Arrays.sort(files);
Map playlist;
for (int i = 0; i < files.length; i++) {
String f = files[i].substring(0,files[i].lastIndexOf(".m3u"));
playlist = new HashMap();
playlist.put("dataTip",
getTotalTracks(playlistsDir + File.separator + files[i]));
playlist.put("label", f);
playlist.put("type", "playlist");
data.add(playlist);
}
}
}
return data;
}
public synchronized List assembleTreeData() {
ArrayList data = new ArrayList();
Map folders = new HashMap();
folders.put("label", "Folders");
folders.put("dataTip", getTotalFolders());
folders.put("children", getFolders());
data.add(folders);
Map genres = new HashMap();
genres.put("label", "Genres");
genres.put("dataTip", getTotalGenres());
genres.put("children", getGenres());
data.add(genres);
Map playlists = new HashMap();
playlists.put("label", "Playlists");
playlists.put("dataTip", getTotalPlaylists());
playlists.put("children", getPlaylists());
data.add(playlists);
return data;
}
public List getByFolder(String folder) throws DAOException {
return assembleFileData("SELECT * FROM files"
+ " WHERE folder = '" + folder.replace("'", "''") + "'"
+ " ORDER BY name"
+ ";");
}
public List getByGenre(String genre) throws DAOException {
return assembleFileData("SELECT * FROM files"
+ " WHERE genre = '" + genre + "'"
+ " ORDER BY name,folder"
+ ";");
}
public List getByPlaylist(String playlist) throws DAOException {
return assembleTracksData(playlist);
}
public synchronized List getBySearch(String search) throws DAOException {
if (search.trim() == "") {
return assembleFileData("SELECT * FROM files ORDER BY name,folder");
}
// quote single-quote with another ('')
search = search.replace("'", "''").toUpperCase();
return assembleFileData("SELECT * FROM files WHERE"
+ " (UCASE(name) LIKE '%" + search + "%') OR "
+ " (UCASE(artist) LIKE '%" + search + "%') OR "
+ " (UCASE(title) LIKE '%" + search + "%') OR "
+ " (UCASE(album) LIKE '%" + search + "%') OR"
+ " (UCASE(comment) LIKE '%" + search + "%')"
+ " ORDER BY name,folder"
+ ";");
}
public List getFolders() throws DAOException {
return assembleFolderData("SELECT * FROM folders ORDER BY folder");
}
public List getGenres() throws DAOException {
return assembleGenreData("SELECT * FROM genres ORDER BY files DESC");
}
public List getPlaylists() throws DAOException {
return assemblePlaylistData();
}
public String getStats() {
refreshDatabase();
String stats;
Connection connection = null;
try {
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
ResultSet rs = null;
// directory
stats = mp3Dir;
int totalFiles = 0;
double totalBitrate = 0;
double milliseconds = 0;
double kilobytes = 0;
int albumless = 0;
int messages = 0;
System.out.println("getStats: sql=SELECT * FROM files");
rs = statement.executeQuery("SELECT * FROM files");
while (rs.next()) {
totalFiles++;
totalBitrate += rs.getInt("bitrate");
milliseconds += rs.getInt("milliseconds");
kilobytes += rs.getInt("kilobytes");
}
// kilobytes
NumberFormat nf = NumberFormat.getInstance();
nf.setMinimumFractionDigits(1);
nf.setMaximumFractionDigits(1);
nf.setGroupingUsed(true);
if (kilobytes < 1024*1024) {
stats = stats + " " + nf.format(kilobytes/1024) + "M";
} else {
stats = stats + " " + nf.format(kilobytes/(1024*1024)) + "G";
}
// files
stats = stats + " " + totalFiles + " files";
// folders
System.out.println("getStats: sql=SELECT COUNT(*) AS rowcount FROM folders");
rs = statement.executeQuery("SELECT COUNT(*) AS rowcount FROM folders");
rs.next();
int totalFolders = rs.getInt("rowcount") ;
rs.close() ;
if (totalFolders == 1) {
stats = stats + " in " + totalFolders + " folder";
} else {
stats = stats + " in " + totalFolders + " folders";
}
// hours
int hours = (int) ((milliseconds/1000)/60)/60;
stats = stats + " " + hours + "hours";
// bitrate
int bitrate = 0;
if (totalFiles > 0) {
bitrate = (int) totalBitrate/totalFiles;
}
stats = stats + "@" + bitrate + "kbs";
}
catch (SQLException x) {
System.out.println("getStats: " + x.getMessage());
x.printStackTrace();
throw new DAOException(x);
}
finally {
ConnectionHelper.close(connection);
}
System.out.println("getStats: " + stats);
return stats;
}
public List getTree() throws DAOException {
return assembleTreeData();
}
public int getTotalFolders() {
int totalFolders = 0;
Connection connection = null;
try {
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
System.out.println("getTotalFolders: sql=SELECT * FROM folders");
ResultSet rs = statement.executeQuery("SELECT * FROM folders");
if (rs != null) while (rs.next()) {
totalFolders++;
}
} catch (SQLException x) {
x.printStackTrace();
throw new DAOException(x);
}
finally {
ConnectionHelper.close(connection);
}
return totalFolders;
}
public int getTotalGenres() {
int totalGenres = 0;
Connection connection = null;
try {
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
System.out.println("getTotalGenres: sql=SELECT * FROM genres");
ResultSet rs = statement.executeQuery("SELECT * FROM genres");
if (rs != null) while (rs.next()) {
totalGenres++;
}
} catch (SQLException x) {
x.printStackTrace();
throw new DAOException(x);
}
finally {
ConnectionHelper.close(connection);
}
return totalGenres;
}
public int getTotalPlaylists() {
int totalPlaylists = 0;
File playlistsFile = new File(playlistsDir);
if (playlistsFile.exists()) {
if (playlistsFile.isDirectory()) try {
String[] children = playlistsFile.list();
for (int i=0; i<children.length; i++) {
if (children[i].endsWith(".m3u")) {
totalPlaylists++;
}
}
} catch (Exception x) {
System.out.println("getTotalPlaylists: " + x.getMessage());
}
}
return totalPlaylists;
}
public int getTotalTracks(String playlistM3u) {
int totalTracks = 0;
File playlistsFile = new File(playlistsDir);
if (playlistsFile.exists() && playlistsFile.isDirectory()) try {
File playlistM3uFile = new File(playlistM3u);
if (!playlistM3uFile.exists()) {
return 0;
}
BufferedReader in = new BufferedReader(new FileReader(playlistM3u));
if (in == null) {
return 0;
}
String str = in.readLine();
while (str != null) {
if (!str.startsWith("#")) {
totalTracks++;
}
str = in.readLine();
}
in.close();
} catch (FileNotFoundException x) {
return 0;
} catch (IOException x) {
System.out.println("totalTracks: " + x.getMessage());
}
return totalTracks;
}
/**
* Read playlist.m3u file, creating a dataTable ready (value=) list.
* @return Value reference pointing to array of playlistItem instances.
*/
public List assembleTracksData(String playlist) {
ArrayList data = new ArrayList();
Connection connection = null;
File playlistsFile = new File(playlistsDir);
if (!playlistsFile.exists() || !playlistsFile.isDirectory()) {
return null;
}
String playlistM3u = playlistsDir + File.separator + playlist + ".m3u";
File playlistM3uFile = new File(playlistM3u);
if (!playlistM3uFile.exists()) {
Object params[] = { playlistM3u };
String msg = msgs.getMessage("DOES_NOT_EXIST", params);
System.out.println("assembleTracksData: " + msg);
return null;
}
try {
FileInputStream fis = new FileInputStream(playlistM3u);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader playlistReader = new BufferedReader(isr);
if (playlistReader == null) {
Object params[] = { playlistM3u };
String msg = msgs.getMessage("UNABLE_TO_OPEN", params);
System.out.println("assembleTracksData: " + msg);
return null;
}
totalSeconds = 0;
int seconds = 0;
int id = 0;
String str = playlistReader.readLine();
String extinf = "";
connection = ConnectionHelper.getConnection();
Statement statement = connection.createStatement();
while (str != null) {
if (str.startsWith("#")) {
if (str.startsWith("#EXTINF:")) {
extinf = str;
int i = str.indexOf(",");
if (i > 8) {
seconds = Integer.parseInt(str.substring(8,i));
}
}
str = playlistReader.readLine();
continue;
}
id = id + 1;
String mins = Long.toString(seconds/60);
String secs = Long.toString(seconds%60);
String duration = "";
if (seconds%60 < 10) {
duration = mins + ":0" + secs;
} else {
duration = mins + ":" + secs;
}
Map file;
if ((str.charAt(0) == '.') && (str.charAt(1) == '.')) {
str = str.substring(3); // strip "../"
}
int i = str.lastIndexOf(File.separator);
if (i < 0) { // no folder (bad playlist item)
file = new HashMap();
file.put("duration", "gone");
file.put("folder", "corrupt path in playlist file");
file.put("name", str);
data.add(file);
} else {
// quote backslash under Windows
String folder = str.substring(0,i);
if (File.separatorChar == '\\') {
folder = folder.replace("\\", "\\\\");
}
// quote single-quote with another next to it ('')
String sql = "SELECT * FROM files"
+ " WHERE (folder = '" + folder.replace("'", "''") + "'"
+ " AND name = '" + str.substring(i+1).replace("'", "''") + "')";
System.out.println("assembleTracksData: sql=" + sql);
ResultSet rs = statement.executeQuery(sql);
if (rs.next()) {
file = putFileData(rs);
data.add(file);
} else {
file = new HashMap();
file.put("duration", "gone");
file.put("folder", folder);
file.put("album", "file no longer available");
file.put("year", "renamed or moved");
file.put("name", str.substring(i+1));
data.add(file);
}
totalSeconds += seconds;
}
str = playlistReader.readLine();
}
playlistReader.close();
} catch (FileNotFoundException x) {
System.out.println("assembleTracksData: " + x.getMessage());
} catch (IOException x) {
System.out.println("assembleTracksData: " + x.getMessage());
} catch (SQLException x) {
System.out.println("assembleTracksData: " + x.getMessage());
throw new DAOException(x);
} catch (Exception x) {
System.out.println("assembleTracksData: " + x.getMessage());
x.printStackTrace();
}
finally {
ConnectionHelper.close(connection);
}
return data;
}
public String getDuration() {
String duration = "";
String hours = Long.toString((totalSeconds/60)/60);
String mins = Long.toString((totalSeconds/60)%60);
String secs = Long.toString(totalSeconds%60);
if (!hours.equals("0")) {
duration += hours + ":";
}
if (mins.length() == 1) {
duration += "0" + mins + ":";
} else {
duration += mins + ":";
}
if (secs.length() == 1) {
duration += "0" + secs;
} else {
duration += secs;
}
return duration;
}
public String newPlaylist() {
File playlistsFile = new File(playlistsDir);
if (!playlistsFile.exists()) {
if (!playlistsFile.mkdirs()) {
Object params[] = { playlistsDir };
String msg = msgs.getMessage("UNABLE_TO_CREATE", params);
Object params2[] = { "playlists.subdir" };
System.out.println("newPlaylist: " + msg);
return null;
}
System.out.println("newPlaylist: mkdirs succeeded.");
} else if (!playlistsFile.isDirectory()) {
Object params[] = { playlistsDir };
String msg = msgs.getMessage("NOT_A_DIRECTORY", params);
Object params2[] = { "playlists.subdir" };
return null;
}
try {
String playlist = "New Playlist";
int i = 0;
File playlistM3uFile;
do {
if (++i > 1) {
playlist = "New Playlist " + i;
}
String playlistM3u = playlistsDir + File.separator + playlist + ".m3u";
playlistM3uFile = new File(playlistM3u);
} while (playlistM3uFile.exists());
if (playlistM3uFile.createNewFile()) {
return playlist;
}
} catch (Exception x) {
System.out.println("newPlaylist: " + x.getMessage());
}
return null;
}
public Boolean renamePlaylist(String playlist, String newname) {
File playlistsFile = new File(playlistsDir);
if (playlistsFile.exists() && playlistsFile.isDirectory()) try {
String playlistM3u = playlistsDir + File.separator + playlist + ".m3u";
File playlistM3uFile = new File(playlistM3u);
if (!playlistM3uFile.exists()) {
System.out.println("renamePlaylist: " + playlistM3u + " does not exist.");
return false;
}
String newnameM3u = playlistsDir + File.separator + newname + ".m3u";
File newnameM3uFile = new File(newnameM3u);
if (newnameM3uFile == null) {
System.out.println("renamePlaylist: Unable to create " + newnameM3u + ".");
return false;
}
if (newnameM3uFile.exists()) {
System.out.println("renamePlaylist: " + newnameM3u + " already exists.");
return false;
}
return playlistM3uFile.renameTo(newnameM3uFile);
} catch (Exception x) {
System.out.println("renamePlaylist: " + x.getMessage());
}
return false;
}
public String deletePlaylist(String playlist) {
File playlistsFile = new File(playlistsDir);
if (playlistsFile.exists() && playlistsFile.isDirectory()) try {
String playlistM3u = playlistsDir + File.separator + playlist + ".m3u";
File playlistM3uFile = new File(playlistM3u);
if (!playlistM3uFile.exists()) {
System.out.println("deletePlaylist: " + playlistM3u + " does not exist.");
return null;
}
playlistM3uFile.delete();
return playlist;
} catch (Exception x) {
System.out.println("deletePlaylist: " + x.getMessage());
}
return null;
}
public Boolean writePlaylist(Boolean append, String playlist, ArrayList data) {
File playlistsFile = new File(playlistsDir);
if (playlistsFile.exists() && playlistsFile.isDirectory()) try {
String playlistM3u = playlistsDir + File.separator + playlist + ".m3u";
File playlistM3uFile = new File(playlistM3u);
if (!playlistM3uFile.exists()) {
System.out.println("renamePlaylist: " + playlistM3u + " does not exist.");
return false;
}
if (!append) { // recreate playlist
playlistM3uFile.delete();
playlistM3uFile.createNewFile();
}
FileWriter playlistM3uWriter = new FileWriter(playlistM3u, true);
if (playlistM3uFile.length() == 0) {
playlistM3uWriter.write("#EXTM3U" + LINEFEED);
}
for (int i = 0; i < data.size(); i++) {
HashMap file = (HashMap) data.get(i);
if (file == null) continue;
String milliseconds, artist, title;
if (file.get("duration").equals("gone")) {
milliseconds = "0";
artist = file.get("folder").toString();
title = file.get("name").toString();
} else {
milliseconds = file.get("milliseconds").toString();
artist = file.get("artist").toString();
title = file.get("title").toString();
}
int seconds = Integer.parseInt(milliseconds)/1000;
playlistM3uWriter.write("#EXTINF:" + seconds + ","
+ artist + " - " + title + LINEFEED);
String path = ".." + File.separator + file.get("folder")
+ File.separator + file.get("name");
playlistM3uWriter.write(path + LINEFEED);
}
playlistM3uWriter.flush();
playlistM3uWriter.close();
return true;
} catch (Exception x) {
System.out.println("writePlaylist: " + x.getMessage());
}
return false;
}
}