diff --git a/projects/robodj/.cvsignore b/projects/robodj/.cvsignore
new file mode 100644
index 00000000..27206ca4
--- /dev/null
+++ b/projects/robodj/.cvsignore
@@ -0,0 +1 @@
+extern
diff --git a/projects/robodj/bin/runjava b/projects/robodj/bin/runjava
index 5edd6850..29176914 100755
--- a/projects/robodj/bin/runjava
+++ b/projects/robodj/bin/runjava
@@ -52,7 +52,7 @@ if (defined $libpath) {
}
# put everything in our class path
-my $classpath = "-classpath $jlib:$root/src/java";
+my $classpath = "-classpath $jlib:$root/dist/classes";
# any zip or jar files in our lib/ directory get added to the class path
if (opendir(DIR, "$root/lib")) {
diff --git a/projects/robodj/build.xml b/projects/robodj/build.xml
new file mode 100644
index 00000000..ee216f6f
--- /dev/null
+++ b/projects/robodj/build.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/robodj/docs/notes.txt b/projects/robodj/docs/notes.txt
new file mode 100644
index 00000000..a599d144
--- /dev/null
+++ b/projects/robodj/docs/notes.txt
@@ -0,0 +1,7 @@
+RoboDJ Notes
+------------
+
+- Catch database errors after the ripping process and allow use to retry
+ commit to database after fixing database unavailability.
+
+- Impersonate a registered CDDB client until we can get "approval".
diff --git a/projects/robodj/lib/.cvsignore b/projects/robodj/lib/.cvsignore
new file mode 100644
index 00000000..d392f0e8
--- /dev/null
+++ b/projects/robodj/lib/.cvsignore
@@ -0,0 +1 @@
+*.jar
diff --git a/projects/robodj/src/java/robodj/Log.java b/projects/robodj/src/java/robodj/Log.java
new file mode 100644
index 00000000..41220aea
--- /dev/null
+++ b/projects/robodj/src/java/robodj/Log.java
@@ -0,0 +1,38 @@
+//
+// $Id: Log.java,v 1.1 2001/03/18 06:58:55 mdb Exp $
+
+package robodj;
+
+/**
+ * A placeholder class that contains a reference to the log object used by
+ * the robodj package.
+ */
+public class Log
+{
+ public static com.samskivert.util.Log log =
+ new com.samskivert.util.Log("robodj");
+
+ /** Convenience function. */
+ public static void debug (String message)
+ {
+ log.debug(message);
+ }
+
+ /** Convenience function. */
+ public static void info (String message)
+ {
+ log.info(message);
+ }
+
+ /** Convenience function. */
+ public static void warning (String message)
+ {
+ log.warning(message);
+ }
+
+ /** Convenience function. */
+ public static void logStackTrace (Throwable t)
+ {
+ log.logStackTrace(com.samskivert.util.Log.WARNING, t);
+ }
+}
diff --git a/projects/robodj/src/java/robodj/convert/EncodeTest.java b/projects/robodj/src/java/robodj/convert/EncodeTest.java
new file mode 100644
index 00000000..56856774
--- /dev/null
+++ b/projects/robodj/src/java/robodj/convert/EncodeTest.java
@@ -0,0 +1,33 @@
+//
+// $Id: EncodeTest.java,v 1.1 2001/03/18 06:58:55 mdb Exp $
+
+package robodj.convert;
+
+import com.samskivert.net.cddb.*;
+
+public class EncodeTest
+{
+ public static void main (String[] args)
+ {
+ if (args.length < 2) {
+ System.err.println("Usage: EncodeTest source.wav dest.mp3");
+ System.exit(-1);
+ }
+
+ try {
+ Encoder encoder = new LameEncoder();
+ ConversionProgressListener listener =
+ new ConversionProgressListener() {
+ public void updateProgress (int percentDone)
+ {
+ System.out.println("Percent done: " +
+ percentDone + "%");
+ }
+ };
+ encoder.encodeTrack(args[0], args[1], listener);
+
+ } catch (Exception e) {
+ System.err.println("Error: " + e);
+ }
+ }
+}
diff --git a/projects/robodj/src/java/robodj/convert/LameEncoder.java b/projects/robodj/src/java/robodj/convert/LameEncoder.java
new file mode 100644
index 00000000..0e6c930d
--- /dev/null
+++ b/projects/robodj/src/java/robodj/convert/LameEncoder.java
@@ -0,0 +1,104 @@
+//
+// $Id: LameEncoder.java,v 1.1 2001/03/18 06:58:55 mdb Exp $
+
+package robodj.convert;
+
+import java.io.*;
+import java.util.ArrayList;
+
+import gnu.regexp.*;
+
+/**
+ * An encoder implementation that uses LAME to do it's job.
+ */
+public class LameEncoder implements Encoder
+{
+ public void encodeTrack (String source, String dest,
+ ConversionProgressListener listener)
+ throws ConvertException
+ {
+ StringBuffer cmd = new StringBuffer("lame");
+ cmd.append(" --nohist"); // we don't want histogram output
+ cmd.append(" -v"); // request variable bitrate encoding
+ cmd.append(" ").append(source); // add source file name
+ cmd.append(" ").append(dest); // add output file name
+
+ // we'll need this for later
+ RE regex;
+ try {
+ // a line of input looks like this
+ // 0/1273 ( 0%)| 0:00/ 0:00...
+ regex = new RE("^\\s*(\\d+)/(\\d+)\\s*\\(.*");
+ } catch (REException ree) {
+ throw new ConvertException("Can't compile regexp?! " + ree);
+ }
+
+ try {
+ // fork off a cdparanoia process to read the TOC
+ Runtime rt = Runtime.getRuntime();
+ Process ripproc = rt.exec(cmd.toString());
+
+ InputStream in = ripproc.getErrorStream();
+ BufferedInputStream bin = new BufferedInputStream(in);
+ DataInputStream din = new DataInputStream(bin);
+
+ // read output from the subprocess
+ String out;
+ int lastReported = 0;
+
+ while ((out = din.readLine()) != null) {
+ // if they don't care about the output then neither do we
+ if (listener == null) {
+ continue;
+ }
+
+ // parse the output
+ REMatch match = regex.getMatch(out);
+ if (match != null) {
+ int offset = -1, total = -1;
+ try {
+ offset = Integer.parseInt(match.toString(1));
+ total = Integer.parseInt(match.toString(2));
+ } catch (NumberFormatException nfe) {
+ System.err.println("Malformed position info: " + out);
+ continue;
+ }
+
+ int pctDone = (100 * offset) / total;
+ if (pctDone - lastReported >= 1) {
+ listener.updateProgress(pctDone);
+ lastReported = pctDone;
+ }
+
+ } else {
+ // System.out.println("Couldn't match: " + out);
+ }
+ }
+
+ // check the return value of the process
+ try {
+ int retval = ripproc.waitFor();
+ if (retval != 0) {
+ // ship off the error output from cdparanoia
+ throw new ConvertException(
+ "Encoder failed: " + retval);
+ }
+
+ } catch (InterruptedException ie) {
+ // why we were interrupted I can only speculate, but we'll
+ // go ahead and freak out anyway
+ throw new ConvertException("Interrupted while waiting for " +
+ "encoder process to exit.");
+ }
+
+ // if everything was successful, report completion
+ if (lastReported < 100) {
+ listener.updateProgress(100);
+ }
+
+ } catch (IOException ioe) {
+ throw new ConvertException(
+ "Error communicating with encoder:\n" + ioe);
+ }
+ }
+}
diff --git a/projects/robodj/src/java/robodj/convert/RipTest.java b/projects/robodj/src/java/robodj/convert/RipTest.java
index 7fdc331d..835b3638 100644
--- a/projects/robodj/src/java/robodj/convert/RipTest.java
+++ b/projects/robodj/src/java/robodj/convert/RipTest.java
@@ -1,5 +1,5 @@
//
-// $Id: RipTest.java,v 1.3 2001/02/06 08:18:00 mdb Exp $
+// $Id: RipTest.java,v 1.4 2001/03/18 06:58:55 mdb Exp $
package robodj.convert;
@@ -24,6 +24,7 @@ public class RipTest
int length = RipUtil.computeDiscLength(info);
try {
+ System.out.println("connecting to: " + hostname);
String rsp = cddb.connect(hostname);
// set the timeout to 30 seconds
@@ -80,7 +81,7 @@ public class RipTest
} else {
// try the CDDB lookup
- lookupCDDB("us.cddb.com", info);
+ lookupCDDB("ca.freedb.org", info);
// rip a track, for fun
int track = 2;
diff --git a/projects/robodj/src/java/robodj/importer/CDDBLookupPanel.java b/projects/robodj/src/java/robodj/importer/CDDBLookupPanel.java
index 7b148519..b0f602ec 100644
--- a/projects/robodj/src/java/robodj/importer/CDDBLookupPanel.java
+++ b/projects/robodj/src/java/robodj/importer/CDDBLookupPanel.java
@@ -1,5 +1,5 @@
//
-// $Id: CDDBLookupPanel.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
+// $Id: CDDBLookupPanel.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
@@ -34,11 +34,24 @@ public class CDDBLookupPanel
cdlabel.setFont(new Font("Helvetica", Font.BOLD, 24));
add(cdlabel, GroupLayout.FIXED);
+ // on the right hand side we want a status display to let the user
+ // know how the CDDB lookup process is going
+ GroupLayout vgl = new VGroupLayout(GroupLayout.STRETCH);
+ vgl.setOffAxisPolicy(GroupLayout.STRETCH);
+ _spanel = new JPanel(vgl);
+
+ JLabel sl = new JLabel("Status", JLabel.LEFT);
+ _spanel.add(sl, GroupLayout.FIXED);
+
// create the "insert cd" text label for the right hand side
_infoText = new JTextArea("Reading CD information...");
_infoText.setLineWrap(true);
_infoText.setEditable(false);
- add(_infoText);
+ // make something for it to scroll around in
+ _spanel.add(new JScrollPane(_infoText));
+
+ // add our panel to the main group
+ add(_spanel);
}
public void wasAddedToFrame (ImporterFrame frame)
@@ -82,7 +95,7 @@ public class CDDBLookupPanel
public Object invoke ()
throws Exception
{
- return CDDBUtil.doCDDBLookup("us.cddb.com", info);
+ return CDDBUtil.doCDDBLookup("ca.freedb.org", info);
}
public boolean abort ()
@@ -97,7 +110,7 @@ public class CDDBLookupPanel
CDDB.Detail[] details = (CDDB.Detail[])result;
// replace the info text with the CD info editor
- remove(_infoText);
+ remove(_spanel);
_infoEditor = new CDInfoEditor(details, _info.length);
add(_infoEditor);
@@ -179,6 +192,7 @@ public class CDDBLookupPanel
protected ImporterFrame _frame;
protected JButton _next;
+ protected JPanel _spanel;
protected JTextArea _infoText;
protected CDInfoEditor _infoEditor;
diff --git a/projects/robodj/src/java/robodj/importer/CDInfoEditor.java b/projects/robodj/src/java/robodj/importer/CDInfoEditor.java
index 2989d77f..31ab8e32 100644
--- a/projects/robodj/src/java/robodj/importer/CDInfoEditor.java
+++ b/projects/robodj/src/java/robodj/importer/CDInfoEditor.java
@@ -1,5 +1,5 @@
//
-// $Id: CDInfoEditor.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
+// $Id: CDInfoEditor.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
@@ -26,10 +26,11 @@ public class CDInfoEditor
JLabel selLabel = new JLabel("Select...");
// create a string array for our combo box
- String[] names = new String[details.length];
+ String[] names = new String[details.length + 1];
for (int i = 0; i < details.length; i++) {
names[i] = details[i].title;
}
+ names[details.length] = "";
_selBox = new JComboBox(names);
selPanel.add(selLabel, GroupLayout.FIXED);
diff --git a/projects/robodj/src/java/robodj/importer/Importer.java b/projects/robodj/src/java/robodj/importer/Importer.java
index c5917b9a..1d00072a 100644
--- a/projects/robodj/src/java/robodj/importer/Importer.java
+++ b/projects/robodj/src/java/robodj/importer/Importer.java
@@ -1,9 +1,15 @@
//
-// $Id: Importer.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
+// $Id: Importer.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
+import java.sql.SQLException;
+import java.util.Properties;
+
import com.samskivert.util.Log;
+import com.samskivert.util.PropertiesUtil;
+
+import robodj.repository.Repository;
/**
* The importer is the GUI-based application for ripping, encoding and
@@ -11,10 +17,40 @@ import com.samskivert.util.Log;
*/
public class Importer
{
+ /**
+ * This is the string we use for the source field of entries created
+ * by the importer.
+ */
+ public static final String ENTRY_SOURCE = "CD";
+
public static Log log = new Log("importer");
+ public static Properties config;
+
+ public static Repository repository;
+
public static void main (String[] args)
{
+ // set up our configuration by hand for now
+ config = new Properties();
+ config.setProperty("repository.db.driver", "org.gjt.mm.mysql.Driver");
+ config.setProperty("repository.db.username", "www");
+ config.setProperty("repository.db.password", "Il0ve2PL@Y");
+ config.setProperty("repository.db.url",
+ "jdbc:mysql://depravity:3306/robodj");
+ config.setProperty("repository.basedir", "/export/robodj/repository");
+
+ // create an interface to the database repository
+ try {
+ Properties dbprops =
+ PropertiesUtil.getSubProperties(config, "repository.db");
+ repository = new Repository(dbprops);
+ } catch (SQLException sqe) {
+ System.err.println("Unable to establish communication " +
+ "with music database: " + sqe);
+ System.exit(-1);
+ }
+
ImporterFrame frame = new ImporterFrame();
InsertCDPanel panel = new InsertCDPanel();
frame.setPanel(panel);
diff --git a/projects/robodj/src/java/robodj/importer/ImporterFrame.java b/projects/robodj/src/java/robodj/importer/ImporterFrame.java
index c1477044..89edb7cf 100644
--- a/projects/robodj/src/java/robodj/importer/ImporterFrame.java
+++ b/projects/robodj/src/java/robodj/importer/ImporterFrame.java
@@ -1,5 +1,5 @@
//
-// $Id: ImporterFrame.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
+// $Id: ImporterFrame.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
@@ -24,7 +24,9 @@ public class ImporterFrame extends JFrame
_top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
// create a container for our control buttons
- _buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+ GroupLayout bgl = new HGroupLayout(GroupLayout.NONE);
+ bgl.setJustification(GroupLayout.RIGHT);
+ _buttonPanel = new JPanel(bgl);
// stick it into the frame
_top.add(_buttonPanel, GroupLayout.FIXED);
@@ -51,7 +53,6 @@ public class ImporterFrame extends JFrame
// then stick the new panel in there
if (panel != null) {
_panel = panel;
- _panel.setBackground(Color.yellow);
_top.add(_panel, 0);
// let the panel know that it was added
_panel.wasAddedToFrame(this);
diff --git a/projects/robodj/src/java/robodj/importer/Panel.java b/projects/robodj/src/java/robodj/importer/Panel.java
index a2093f3b..1d9a375f 100644
--- a/projects/robodj/src/java/robodj/importer/Panel.java
+++ b/projects/robodj/src/java/robodj/importer/Panel.java
@@ -1,8 +1,10 @@
//
-// $Id: Panel.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
+// $Id: Panel.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
+import javax.swing.JPanel;
+
public class Panel extends JPanel
{
}
diff --git a/projects/robodj/src/java/robodj/importer/RipPanel.java b/projects/robodj/src/java/robodj/importer/RipPanel.java
index 1bdb747b..f66add90 100644
--- a/projects/robodj/src/java/robodj/importer/RipPanel.java
+++ b/projects/robodj/src/java/robodj/importer/RipPanel.java
@@ -1,11 +1,12 @@
//
-// $Id: RipPanel.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
+// $Id: RipPanel.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.io.File;
import java.net.URL;
import java.util.ArrayList;
@@ -16,6 +17,7 @@ import com.samskivert.swing.util.*;
import com.samskivert.swing.*;
import com.samskivert.util.StringUtil;
+import robodj.Log;
import robodj.convert.*;
import robodj.repository.*;
@@ -30,39 +32,324 @@ public class RipPanel
setLayout(gl);
// create our label for the left hand side
- JLabel cdlabel = new JLabel("Ripping", JLabel.CENTER);
+ JLabel cdlabel = new JLabel("Converting", JLabel.CENTER);
cdlabel.setFont(new Font("Helvetica", Font.BOLD, 24));
add(cdlabel, GroupLayout.FIXED);
+ // create a panel for the progress display
+ GroupLayout vgl = new VGroupLayout(GroupLayout.STRETCH);
+ vgl.setOffAxisPolicy(GroupLayout.STRETCH);
+ JPanel ppanel = new JPanel(vgl);
+
+ // create the overall progress indicator
+ JLabel opl = new JLabel("Overall progress", JLabel.LEFT);
+ ppanel.add(opl, GroupLayout.FIXED);
+ // overall progress assumes equal time spent ripping and encoding
+ // each track on the disc. not entirely accurate, but reasonable
+ // for giving a general idea of how far along we are
+ _oprogress = new JProgressBar(0, 200*info.length);
+ ppanel.add(_oprogress, GroupLayout.FIXED);
+
+ // create the task progress indicator
+ JLabel tpl = new JLabel("Track progress", JLabel.LEFT);
+ ppanel.add(tpl, GroupLayout.FIXED);
+ _progress = new JProgressBar(0, 100);
+ ppanel.add(_progress, GroupLayout.FIXED);
+
+ // create the status log
+ JLabel sl = new JLabel("Status", JLabel.LEFT);
+ ppanel.add(sl, GroupLayout.FIXED);
+ _statusLog = new JTextArea();
+ _statusLog.setLineWrap(true);
+ _statusLog.setEditable(false);
+ // make something for it to scroll around in
+ ppanel.add(new JScrollPane(_statusLog));
+
+ // add our panel to the main group
+ add(ppanel);
+
// save this stuff for later
_info = info;
_entry = entry;
}
+ protected void postAsyncStatus (final String status)
+ {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run ()
+ {
+ _statusLog.append(status + "\n");
+ }
+ });
+ }
+
+ protected void postAsyncProgress (final int overallComplete,
+ final int taskComplete)
+ {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run ()
+ {
+ // update our progress indicators
+ _oprogress.setValue(overallComplete);
+ _progress.setValue(taskComplete);
+ }
+ });
+ }
+
+ protected static String createTempPath (int trackno, String ext)
+ {
+ return "/tmp/track" + trackno + "." + ext;
+ }
+
+ /** Handles the ripping and encoding of the tracks. */
+ protected class RipperTask
+ implements Task, ConversionProgressListener
+ {
+ public RipperTask (Ripper.TrackInfo[] info)
+ {
+ _info = info;
+ }
+
+ public Object invoke ()
+ throws Exception
+ {
+ Ripper ripper = new CDParanoiaRipper();
+ Encoder encoder = new LameEncoder();
+
+ for (int i = 0; i < _info.length; i++) {
+ _track = i+1;
+
+ // rip the track
+ _encoding = false;
+ // it takes a second or so for the ripper to start
+ // reporting progress, so we clear out the progress
+ // indicator so that the 100% progress of the previous
+ // track doesn't look like it applies to this new track
+ // while we're spinning up
+ updateProgress(0);
+ postAsyncStatus("Ripping track " + _track + "...");
+ String tpath = createTempPath(_track, "wav");
+ ripper.ripTrack(_info, _track, tpath, this);
+
+ // then encode it
+ _encoding = true;
+ updateProgress(0);
+ postAsyncStatus("Encoding track " + _track + "...");
+ String dpath = createTempPath(_track, "mp3");
+ encoder.encodeTrack(tpath, dpath, this);
+
+ // remove the source wav file
+ File tfile = new File(tpath);
+ if (!tfile.delete()) {
+ postAsyncStatus("Unable to remove temp file " +
+ "for track " + _track + ".");
+ }
+ }
+
+ return null;
+ }
+
+ public boolean abort ()
+ {
+ // no abort presently
+ return false;
+ }
+
+ public void updateProgress (int percentComplete)
+ {
+ // first add completeness for tracks we've already done
+ int overallComplete = (_track-1) * 200;
+ // if we're encoding, then we finished ripping this track
+ if (_encoding) {
+ overallComplete += 100;
+ }
+ // finally add the percent complete for the current task
+ overallComplete += percentComplete;
+ // and pass it all on to the UI for display
+ postAsyncProgress(overallComplete, percentComplete);
+ }
+
+ protected Ripper.TrackInfo[] _info;
+ protected int _track;
+ protected boolean _encoding;
+ }
+
+ /** Commits the completed entry into the repository. */
+ protected class CommitterTask
+ implements Task
+ {
+ public CommitterTask (Entry entry, Ripper.TrackInfo[] info)
+ {
+ _entry = entry;
+ _info = info;
+ }
+
+ public Object invoke ()
+ throws Exception
+ {
+ int entryid = -1;
+
+ try {
+ // determine the target directory for the mp3 files
+ String rbase =
+ Importer.config.getProperty("repository.basedir");
+ if (StringUtil.blank(rbase)) {
+ throw new Exception("No mp3 repository directory " +
+ "specified.");
+ }
+
+ // ensure the repository directory exists
+ File rbf = new File(rbase);
+ if (!rbf.exists() || !rbf.isDirectory()) {
+ throw new Exception("Repository base directory '" +
+ rbase + "' is not valid.");
+ }
+
+ postAsyncStatus("Creating repository directory.");
+ // create the hash directory
+ int hcode = _entry.title.hashCode();
+ if (hcode < 0) {
+ hcode *= -1;
+ }
+ System.out.println(Integer.toHexString(255 % 0xFF));
+ String hash = Integer.toHexString(hcode % 0xFF);
+ StringBuffer tpath = new StringBuffer(rbase);
+ if (tpath.charAt(tpath.length()-1) != '/') {
+ tpath.append("/");
+ }
+ tpath.append(hash);
+
+ File tdir = new File(tpath.toString());
+ if (!tdir.exists()) {
+ if (!tdir.mkdir()) {
+ throw new Exception("Unable to create target " +
+ "directory: " + tpath);
+ }
+
+ } else {
+ // make sure it's a directory
+ if (!tdir.isDirectory()) {
+ throw new Exception("Target directory '" + tpath +
+ "' is not valid.");
+ }
+ }
+
+ // fill in the entry source since we ripped this from CD
+ _entry.source = Importer.ENTRY_SOURCE;
+
+ // fill in blanks for the locations of the tunes because
+ // we won't know the name of the directory until we are
+ // assigned an entry id
+ for (int i = 0; i < _entry.songs.length; i++) {
+ _entry.songs[i].location = "";
+ }
+
+ postAsyncStatus("Creating database entry.");
+ // insert the entry into the repository so that we get the
+ // proper entry id which we'll need to put the tracks in their
+ // proper place in the repository
+ Importer.repository.insertEntry(_entry);
+ // track this so that we can clean up in case of failure
+ entryid = _entry.entryid;
+
+ // now that we have an entry id, fully construct the
+ // target path
+ tpath.append("/").append(_entry.entryid);
+ tdir = new File(tpath.toString());
+ if (!tdir.mkdir()) {
+ throw new Exception("Unable to create target " +
+ "directory: " + tpath);
+ }
+
+ postAsyncStatus("Moving tracks into repository directory.");
+ // move the tracks into the target directory
+ tpath.append("/");
+ for (int i = 0; i < _entry.songs.length; i++) {
+ int tno = i+1;
+
+ // figure out the necessary paths
+ String npath = tpath.toString() + tno + ".mp3";
+ String opath = createTempPath(tno, "mp3");
+
+ // move the file
+ File ofile = new File(opath);
+ File nfile = new File(npath);
+ if (!ofile.renameTo(nfile)) {
+ throw new Exception("Unable to move track " + tno +
+ " to target location: " + npath);
+ }
+
+ // and update the song object
+ _entry.songs[i].location = npath;
+ }
+
+ // finally update the entry in the database
+ Importer.repository.updateEntry(_entry);
+ // and clear out the entryid to indicate success
+ entryid = -1;
+
+ postAsyncStatus("Import complete.");
+ return null;
+
+ } finally {
+ // if we got halfway through creating our entry, remove it
+ // from the database
+ if (entryid != -1) {
+ Importer.repository.deleteEntry(_entry);
+ }
+ }
+ }
+
+ public boolean abort ()
+ {
+ // we don't support aborting. this shouldn't take long at all
+ return false;
+ }
+
+ protected Entry _entry;
+ protected Ripper.TrackInfo[] _info;
+ }
+
public void wasAddedToFrame (ImporterFrame frame)
{
// keep this for later
_frame = frame;
- frame.addControlButton("Cancel", "cancel", this);
+ // add our next and cancel buttons
+ _cancel = frame.addControlButton("Cancel", "cancel", this);
_next = frame.addControlButton("Next...", "next", this);
_next.setEnabled(false);
+
+ // create our info task and set it a running
+ Task ripTask = new RipperTask(_info);
+ TaskMaster.invokeTask("convert", ripTask, this);
}
public void taskCompleted (String name, Object result)
{
- if (name.equals("getinfo")) {
+ if (name.equals("convert")) {
+ // yay! we're all done. commit the entry to the repository
+ Task commitTask = new CommitterTask(_entry, _info);
+ TaskMaster.invokeTask("commit", commitTask, this);
- } else if (name.equals("cddb_lookup")) {
+ } else if (name.equals("commit")) {
+ // we're all done. fix up the buttons and call it good
+ _cancel.setEnabled(false);
+ _next.setLabel("Exit");
+ _next.setEnabled(true);
}
}
public void taskFailed (String name, Throwable exception)
{
- if (name.equals("getinfo")) {
-
- } else if (name.equals("cddb_lookup")) {
- }
+ String msg;
+ if (Exception.class.equals(exception.getClass())) {
+ msg = exception.getMessage();
+ } else {
+ msg = exception.toString();
+ }
+ _statusLog.append("Error: " + msg + "\n");
+ Log.logStackTrace(exception);
}
public void actionPerformed (ActionEvent e)
@@ -72,6 +359,7 @@ public class RipPanel
System.exit(0);
} else if (cmd.equals("next")) {
+ System.exit(0);
} else {
System.out.println("Unknown action event: " + cmd);
@@ -80,6 +368,12 @@ public class RipPanel
protected ImporterFrame _frame;
protected JButton _next;
+ protected JButton _cancel;
+ protected JLabel _actionLabel;
+
+ protected JProgressBar _oprogress;
+ protected JProgressBar _progress;
+ protected JTextArea _statusLog;
protected Ripper.TrackInfo[] _info;
protected Entry _entry;
diff --git a/projects/robodj/src/java/robodj/repository/Repository.java b/projects/robodj/src/java/robodj/repository/Repository.java
index 08263744..1cbf502d 100644
--- a/projects/robodj/src/java/robodj/repository/Repository.java
+++ b/projects/robodj/src/java/robodj/repository/Repository.java
@@ -1,5 +1,5 @@
//
-// $Id: Repository.java,v 1.2 2001/02/13 05:48:29 mdb Exp $
+// $Id: Repository.java,v 1.3 2001/03/18 06:58:55 mdb Exp $
package robodj.repository;
@@ -91,39 +91,30 @@ public class Repository extends MySQLRepository
* and the song objects) will be filled in with the entryid of the
* newly created entry.
*/
- public void insertEntry (Entry entry)
+ public void insertEntry (final Entry entry)
throws SQLException
{
- try {
- // insert the entry into the entry table
- _etable.insert(entry);
+ execute(new Operation () {
+ public void invoke () throws SQLException
+ {
+ // insert the entry into the entry table
+ _etable.insert(entry);
- // update the entryid now that it's known
- entry.entryid = lastInsertedId();
+ // update the entryid now that it's known
+ entry.entryid = lastInsertedId();
- // and insert all of it's songs into the songs table
- if (entry.songs != null) {
- for (int i = 0; i < entry.songs.length; i++) {
- // insert the proper entryid
- entry.songs[i].entryid = entry.entryid;
- _stable.insert(entry.songs[i]);
- // find out what songid was assigned
- entry.songs[i].songid = lastInsertedId();
- }
- }
-
- _session.commit();
-
- } catch (SQLException sqe) {
- // back out our changes if something got hosed
- _session.rollback();
- throw sqe;
-
- } catch (RuntimeException rte) {
- // back out our changes if something got hosed
- _session.rollback();
- throw rte;
- }
+ // and insert all of it's songs into the songs table
+ if (entry.songs != null) {
+ for (int i = 0; i < entry.songs.length; i++) {
+ // insert the proper entryid
+ entry.songs[i].entryid = entry.entryid;
+ _stable.insert(entry.songs[i]);
+ // find out what songid was assigned
+ entry.songs[i].songid = lastInsertedId();
+ }
+ }
+ }
+ });
}
/**
@@ -136,57 +127,40 @@ public class Repository extends MySQLRepository
* @see addSongToEntry
* @see removeSongFromEntry
*/
- public void updateEntry (Entry entry)
+ public void updateEntry (final Entry entry)
throws SQLException
{
- try {
- // update the entry
- _etable.update(entry);
+ execute(new Operation () {
+ public void invoke () throws SQLException
+ {
+ // update the entry
+ _etable.update(entry);
- // and the entry's songs
- if (entry.songs != null) {
- for (int i = 0; i < entry.songs.length; i++) {
- _stable.update(entry.songs[i]);
- }
- }
-
- _session.commit();
-
- } catch (SQLException sqe) {
- // back out our changes if something got hosed
- _session.rollback();
- throw sqe;
-
- } catch (RuntimeException rte) {
- // back out our changes if something got hosed
- _session.rollback();
- throw rte;
- }
+ // and the entry's songs
+ if (entry.songs != null) {
+ for (int i = 0; i < entry.songs.length; i++) {
+ _stable.update(entry.songs[i]);
+ }
+ }
+ }
+ });
}
/**
* Removes the entry (and all associated songs) from the database.
*/
- public void deleteEntry (Entry entry)
+ public void deleteEntry (final Entry entry)
throws SQLException
{
- try {
- // remove the entry from the entry table and the foreign key
- // constraints will automatically remove all of the
- // corresponding songs
- _etable.delete(entry);
- _session.commit();
-
- } catch (SQLException sqe) {
- // back out our changes if something got hosed
- _session.rollback();
- throw sqe;
-
- } catch (RuntimeException rte) {
- // back out our changes if something got hosed
- _session.rollback();
- throw rte;
- }
+ execute(new Operation () {
+ public void invoke () throws SQLException
+ {
+ // remove the entry from the entry table and the foreign
+ // key constraints will automatically remove all of the
+ // corresponding songs
+ _etable.delete(entry);
+ }
+ });
}
/**
@@ -201,81 +175,55 @@ public class Repository extends MySQLRepository
*
* @see updateSong
*/
- public void addSongToEntry (Entry entry, Song song)
+ public void addSongToEntry (final Entry entry, final Song song)
throws SQLException
{
- try {
- // fill in the appropriate entry id value
- song.entryid = entry.entryid;
+ execute(new Operation () {
+ public void invoke () throws SQLException
+ {
+ // fill in the appropriate entry id value
+ song.entryid = entry.entryid;
- // and stick the song into the database
- _stable.insert(song);
- // communicate the songid back to the caller
- song.songid = lastInsertedId();
- _session.commit();
-
- } catch (SQLException sqe) {
- // back out our changes if something got hosed
- _session.rollback();
- throw sqe;
-
- } catch (RuntimeException rte) {
- // back out our changes if something got hosed
- _session.rollback();
- throw rte;
- }
+ // and stick the song into the database
+ _stable.insert(song);
+ // communicate the songid back to the caller
+ song.songid = lastInsertedId();
+ }
+ });
}
/**
* Updates the specified song individually. The songid and entryid
* parameters should already be set to the appropriate values.
*/
- public void updateSong (Song song)
+ public void updateSong (final Song song)
throws SQLException
{
- try {
- _stable.update(song);
- _session.commit();
-
- } catch (SQLException sqe) {
- // back out our changes if something got hosed
- _session.rollback();
- throw sqe;
-
- } catch (RuntimeException rte) {
- // back out our changes if something got hosed
- _session.rollback();
- throw rte;
- }
+ execute(new Operation () {
+ public void invoke () throws SQLException
+ {
+ _stable.update(song);
+ }
+ });
}
/**
* Creates a category with the specified name and returns the id of
* that new category.
*/
- public int createCategory (String name)
+ public int createCategory (final String name)
throws SQLException
{
- try {
- Category cat = new Category();
- cat.name = name;
- _ctable.insert(cat);
+ execute(new Operation () {
+ public void invoke () throws SQLException
+ {
+ Category cat = new Category();
+ cat.name = name;
+ _ctable.insert(cat);
+ }
+ });
- int categoryid = lastInsertedId();
- _session.commit();
-
- return categoryid;
-
- } catch (SQLException sqe) {
- // back out our changes if something got hosed
- _session.rollback();
- throw sqe;
-
- } catch (RuntimeException rte) {
- // back out our changes if something got hosed
- _session.rollback();
- throw rte;
- }
+ return lastInsertedId();
}
/**