package org.limewire.ui.swing.library.navigator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.limewire.core.api.FilePropertyKey;
import org.limewire.core.api.library.LocalFileItem;
import org.limewire.core.api.library.LocalFileList;
import org.limewire.io.IOUtils;
import org.limewire.ui.swing.util.BackgroundExecutorService;
import org.limewire.util.FileUtils;
class M3UList {
private static final String M3U_HEADER = "#EXTM3U";
private static final String SONG_DELIM = "#EXTINF";
private static final String SEC_DELIM = ":";
private final File file;
private final LocalFileList localFileList;
public M3UList(File file, LocalFileList localFileList) {
this.file = file;
this.localFileList = localFileList;
}
public void load() {
BackgroundExecutorService.execute(new Runnable(){
public void run() {
try {
List<File> m3uFileList = loadInternalList();
for(File file : m3uFileList)
localFileList.addFile(file);
} catch (Exception e) {
//TODO: give user feedback
}
}
});
}
public void save() {
final List<LocalFileItem> writeableList;
localFileList.getModel().getReadWriteLock().readLock().lock();
try {
writeableList = new ArrayList<LocalFileItem>(localFileList.getModel().subList(0, localFileList.getModel().size()));
} finally {
localFileList.getModel().getReadWriteLock().readLock().unlock();
}
BackgroundExecutorService.execute(new Runnable(){
public void run() {
try {
saveInternalList(writeableList);
} catch (Exception e) {
//TODO: notify user
}
}
});
}
/**
* Attempts to write the list of files to an m3u list.
* Follows the standard m3u protocol.
*/
private void saveInternalList(List<LocalFileItem> writeableList) throws Exception {
PrintWriter m3uFile = null;
try {
m3uFile = new PrintWriter(new FileWriter(file.getCanonicalPath(), false));
m3uFile.write(M3U_HEADER);
m3uFile.println();
for(LocalFileItem currFile : writeableList) {
// only save files that are local to the file system
if(currFile.getFile().isFile() && !currFile.isIncomplete()){
File locFile = currFile.getFile();
// first line of song description...
m3uFile.write(SONG_DELIM);
m3uFile.write(SEC_DELIM);
// try to write out seconds info....
if(currFile.getPropertyString(FilePropertyKey.LENGTH) != null) {
m3uFile.write("" + currFile.getPropertyString(FilePropertyKey.LENGTH) + ",");
} else {
m3uFile.write("-1,");
}
m3uFile.write(currFile.getName());
m3uFile.println();
// canonical path follows...
m3uFile.write(locFile.getCanonicalPath());
m3uFile.println();
}
}
} finally {
IOUtils.close(m3uFile);
}
}
/**
* Attempts to open the current m3u list and locate and load
* all the files described within that list. Returns the list
* of Files that were succesfully found.
*/
private List<File> loadInternalList() throws Exception {
List<File> m3uFileList = new ArrayList<File>();
BufferedReader m3uFile = null;
try {
m3uFile = new BufferedReader(new FileReader(file));
String currLine = null;
currLine = m3uFile.readLine();
if (currLine == null || !(currLine.startsWith(M3U_HEADER) || currLine.startsWith(SONG_DELIM)))
throw new IOException();
if(currLine.startsWith(M3U_HEADER))
currLine = m3uFile.readLine();
for(; currLine != null; currLine = m3uFile.readLine()) {
if (currLine.startsWith(SONG_DELIM)) {
currLine = m3uFile.readLine();
if(currLine == null)
break;
File currentFile = new File(currLine);
if (currentFile.exists() && !currentFile.isDirectory())
m3uFileList.add(currentFile);
else {
// try relative path to the playlist
currentFile = new File(file.getParentFile().getAbsolutePath(), currentFile.getPath());
if (currentFile.exists() && !currentFile.isDirectory() &&
FileUtils.isReallyInParentPath(file.getParentFile(), currentFile))
m3uFileList.add(currentFile);
}
}
}
} finally {
IOUtils.close(m3uFile);
}
return m3uFileList;
}
}