Migrated samskivert into its own, sensibly organized, repository.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@1774 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2006-01-30 19:52:55 +00:00
parent 5966766e26
commit 9d62b407e7
413 changed files with 0 additions and 9443 deletions
View File
-3
View File
@@ -1,3 +0,0 @@
extern
build-stamp
.jde-project.el
-31
View File
@@ -1,31 +0,0 @@
RoboDJ 1.2 (March 03, 2002)
NEW FEATURES
* (importer) Added support for adding ID3 tags to MP3 files after
they are encoded.
* (chooser) Gave the UI a major facelift:
- added icons for most buttons;
- fixed layout to work more nicely;
- made controls reflect actual state of the music daemon (paused
versus playing, etc.).
* (importer) Added ability to back up from the CDDB panel to the
"insert CD" panel.
RoboDJ 1.1 (February 22, 2002)
NEW FEATURES
* (chooser) Added support for removing an entire CD at at time
from the playlist browser.
* (chooser) Added ability to search repository for entries where
album, artist or song title contains a text string.
RoboDJ 1.0 (February 21, 2002)
INITIAL RELEASE
$Id: NEWS,v 1.2 2002/03/03 21:17:03 mdb Exp $
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/perl -w
#
# $Id: append,v 1.2 2001/03/22 03:00:25 mdb Exp $
#
# Appends the supplied song or songs to the playlist of a running MP3
# daemon.
use strict;
use IO::Socket;
my $usage = "Usage: $0 mp3_file [mp3_file ...]\n";
my $path = shift or die $usage;
# determine our music daemon host and port
my $host = "localhost";
if (defined $ENV{"MUSICD_HOST"}) {
$host = $ENV{"MUSICD_HOST"};
}
my $port = 2500;
if (defined $ENV{"MUSICD_PORT"}) {
$port = $ENV{"MUSICD_PORT"};
}
# establish a socket connection with the server
my $sock = new IO::Socket::INET(PeerAddr => $host,
PeerPort => $port,
Proto => "tcp");
if (!defined $sock) {
die "Unable to connect to music server on $host:$port.\n";
}
do {
# send the command
print $sock "APPEND $path\n";
# print the response
print scalar <$sock>;
} while ($path = shift);
close $sock;
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
`dirname $0`/runjava $* robodj.chooser.Chooser
-27
View File
@@ -1,27 +0,0 @@
#!/usr/bin/perl -w
#
# $Id: delete,v 1.1 2002/03/03 04:56:43 mdb Exp $
#
# Deletes an entry from the repository. Must be run on the machine that
# hosts the repository so that it can delete the files.
my $usage = "Usage: $0 repodir db_username db_password entryid\n";
my $repodir = shift or die $usage;
my $username = shift or die $usage;
my $password = shift or die $usage;
my $entryid = shift or die $usage;
if (! -d $repodir) {
die "'$repodir' not a valid repository directory.\n";
}
invoke_sql("delete from entries where entryid=$entryid");
invoke_sql("delete from songs where entryid=$entryid");
system("rm -rf $repodir/*/$entryid");
sub invoke_sql {
my ($sql) = @_;
system("mysql -u $username -p$password -e \"$sql\" robodj") == 0
or die "Error invoking 'mysql'.";
}
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
`dirname $0`/runjava robodj.importer.Importer
-50
View File
@@ -1,50 +0,0 @@
#!/usr/bin/perl -w
#
# $Id: mpcmd,v 1.2 2001/03/22 03:00:25 mdb Exp $
#
# Appends the supplied song or songs to the playlist of a running MP3
# daemon.
use strict;
use IO::Socket;
my $usage = "Usage: $0 COMMAND [ARGUMENT ...]\n";
my $command = shift or die $usage;
# determine our music daemon host and port
my $host = "localhost";
if (defined $ENV{"MUSICD_HOST"}) {
$host = $ENV{"MUSICD_HOST"};
}
my $port = 2500;
if (defined $ENV{"MUSICD_PORT"}) {
$port = $ENV{"MUSICD_PORT"};
}
# establish a socket connection with the server
my $sock = new IO::Socket::INET(PeerAddr => $host,
PeerPort => $port,
Proto => "tcp");
if (!defined $sock) {
die "Unable to connect to music server on $host:$port.\n";
}
# send the command
print $sock "$command " . join(" ", @ARGV) . "\n";
# PLAYLIST has a multiline response, others are single line
if ($command eq "PLAYLIST") {
my $rsp = <$sock>;
print $rsp;
if ($rsp =~ m/200 Playlist songs: (\d+)/) {
my $i;
for ($i = 0; $i < $1; $i++) {
print scalar <$sock>;
}
}
} else {
print scalar <$sock>;
}
close $sock;
-3
View File
@@ -1,3 +0,0 @@
#!/bin/sh
`dirname $0`/runjava $* robodj.server.MusicDaemon
-55
View File
@@ -1,55 +0,0 @@
#!/usr/bin/perl -w
#
# $Id: quickrip,v 1.1 2002/01/19 04:35:53 mdb Exp $
#
# Rips and encodes a CD and places it into the repository directory having
# been given some necessary parameters.
my $usage = "$0 branchdir entryid [trackno]\n";
my $root = "/export/robodj/repository";
# read our arguments
my $branchdir = shift or die $usage;
my $entryid = shift or die $usage;
my $trackno = shift;
# figure out how many tracks there are to rip
my $trackcount = 0;
open(SCAN, "cdparanoia -Q 2>&1|") or die "Can't invoke cdparanoia: $!\n";
while (<SCAN>) {
# parse track info lines just to get the track counts
if (/^\s*(\d+)\.\s+(\d+)\s\[\S*\]\s+(\d+)/) {
$trackcount = $1;
}
}
# create the target directory
my $target = "$root/$branchdir/$entryid";
system("mkdir -p $target");
# do our main business
if (defined $trackno) {
# either rip a single track
rip_track($trackno);
} else {
# or rip the whole kit and kaboodle
for ($i = 1; $i <= $trackcount; $i++) {
rip_track($i);
}
}
sub rip_track
{
my ($track) = @_;
my $tno = sprintf("%02d", $track);
my $tmp = "/tmp/track$tno";
# rip the track
system("cdparanoia -w $track $tmp.wav\n");
# encode it
system("lame --nohist -v $tmp.wav $tmp.mp3\n");
# move it into the repository
system("mv $tmp.mp3 $target/$tno.mp3");
# and clean up after ourselves
unlink("$tmp.wav");
}
-47
View File
@@ -1,47 +0,0 @@
#!/bin/sh
#
# /usr/bin/rdjbrowse
#
# Launches the RoboDJ music browser and playlist manager
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=robodj
DESC="Robodj game server"
PIDFILE="/var/run/$NAME.pid"
CLASS=robodj.chooser.Chooser
LOGFILE=/var/log/$NAME/stdout.log
ROBODJ_HOME=/usr/share/$NAME
# The following varibales can we overwritten in /etc/default/robodj
MUSICD_HOST=localhost
MUSICD_PORT=2500
# The first existing directory is used for JAVA_HOME
JDK_DIRS="/usr/local/jdk1.4 /usr/local/jdk1.3 /usr/lib/j2se/1.3"
# overwrite settings from default file
if [ -f /etc/default/robodj ]; then
. /etc/default/robodj
fi
# Look for the right JVM to
for jdir in $JDK_DIRS; do
if [ -d "$jdir" -a -z "${JAVA_HOME}" ]; then
JAVA_HOME=$jdir
fi
done
JAVA="$JAVA_HOME/bin/java"
test -f $DAEMON || exit 0
# Start with the standard Java classes
CLASSPATH="$JAVA_HOME/jre/lib/rt.jar"
# Add all JAR files in /usr/share/robodj/lib to the CLASSPATH
for jar in $ROBODJ_HOME/lib/*.jar; do
if [ -e $jar ]; then
CLASSPATH=$jar:$CLASSPATH
fi
done
export CLASSPATH
$JAVA -Dmusicd_host=$MUSICD_HOST -Dmusicd_port=$MUSICD_PORT $CLASS
-46
View File
@@ -1,46 +0,0 @@
#!/bin/sh
#
# /usr/bin/rdjbrowse
#
# Launches the RoboDJ music browser and playlist manager
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=robodj
DESC="Robodj game server"
PIDFILE="/var/run/$NAME.pid"
CLASS=robodj.importer.Importer
LOGFILE=/var/log/$NAME/stdout.log
ROBODJ_HOME=/usr/share/$NAME
# The following varibales can we overwritten in /etc/default/robodj
# The first existing directory is used for JAVA_HOME
JDK_DIRS="/usr/local/jdk1.4 /usr/lib/j2se/1.3"
# overwrite settings from default file
if [ -f /etc/default/robodj ]; then
. /etc/default/robodj
fi
# Look for the right JVM to
for jdir in $JDK_DIRS; do
if [ -d "$jdir" -a -z "${JAVA_HOME}" ]; then
JAVA_HOME=$jdir
fi
done
JAVA="$JAVA_HOME/bin/java"
test -f $DAEMON || exit 0
# Start with the standard Java classes
CLASSPATH="$JAVA_HOME/jre/lib/rt.jar"
# Add all JAR files in /usr/share/robodj/lib to the CLASSPATH
for jar in $ROBODJ_HOME/lib/*.jar; do
if [ -e $jar ]; then
CLASSPATH=$jar:$CLASSPATH
fi
done
export CLASSPATH
$JAVA $CLASS
-107
View File
@@ -1,107 +0,0 @@
#!/usr/bin/perl -w
use Getopt::Std;
my $usage = "Usage: $0 [-p pid_file] [-r root_directory] args\n";
# locations of stuff
chomp($location = `dirname $0`);
# get the server root by popping the /bin off of our parent directory
@parts = split(/\//, $location);
pop(@parts);
my $root = join("/", @parts);
my $jhome = $ENV{"JAVA_HOME"};
# make sure JAVA_HOME is set
if (!defined $jhome) {
warn "$0: Error: No JAVA_HOME specified!\n";
warn "\n";
warn "You must set your JAVA_HOME environment variable to the\n";
warn "the absolute path of your JDK installation. For example:\n";
warn "\n";
warn " % JAVA_HOME=/usr/local/jdk1.2\n";
warn " % export JAVA_HOME\n";
die "\n";
}
# make sure it's set to a directory
if (! -d $jhome) {
die "$0: Can't find a java interpreter in '$jhome'.\n";
}
my $java = "$jhome/bin/java";
my $jlib = "$jhome/lib/classes.zip";
# determine our machine architecture
my $ostype = `uname -s`;
my $machtype = `uname -m`;
chomp($ostype);
chomp($machtype);
my $arch = "$machtype-$ostype";
# add our native libraries to the runtime library path
my $libs = "$root/lib/$arch";
my $libpath = $ENV{"LD_LIBRARY_PATH"};
if (defined $libpath) {
$ENV{"LD_LIBRARY_PATH"} = "$libs:$libpath";
} else {
$ENV{"LD_LIBRARY_PATH"} = $libs;
}
# put everything in our class path
my $classpath = "-classpath $root/dist/classes";
# add zip and jar files from our lib/ directory and the system lib/ directory
my @dirs = ( "$root/lib", $ENV{"JAVA_LIBS"} );
foreach $dir (@dirs) {
next unless (defined $dir);
if (opendir(DIR, $dir)) {
foreach $lib (grep { /.(zip|jar)/ && -f "$dir/$_" } readdir(DIR)) {
$classpath .= ":$dir/$lib";
}
closedir DIR;
}
}
# finally add the standard classes
$classpath = "$classpath:$jlib";
# specify our application root (the resource manager needs this)
my $rootarg = "-Dresource_url=file:$root/rsrc";
my $pid_file = undef;
my $i = 0;
# strip out the -p and -r args (we'd use getopt() but the damned thing
# provides no way of escaping arguments so that we can pass args to
# runjava that get passed down to the JVM)
for ($i = 0; $i < @ARGV; $i++) {
my $arg = $ARGV[$i];
# stop when we see -- (and strip it out because Java don't dig --)
if ($arg eq "--") {
splice(@ARGV, $i, 1);
last;
}
if ($arg eq "-p") {
$pid_file = $ARGV[$i+1];
splice(@ARGV, $i, 2);
$i -= 1; # decrement i so that things stay in sync
} elsif ($arg eq "-r") {
$rootarg = "-Dapplication.root=" . $ARGV[$i+1];
splice(@ARGV, $i, 2);
$i -= 1; # decrement i so that things stay in sync
}
}
# log the pid file if requested to do so
print `echo $$ > $pid_file` if (defined $pid_file);
my $cmd = "$java -mx256M $classpath $rootarg " . join(" ", @ARGV);
# print "$cmd\n";
exec($cmd);
-67
View File
@@ -1,67 +0,0 @@
#!/usr/bin/perl -w
#
# $Id: setid3,v 1.3 2002/03/03 05:54:33 mdb Exp $
#
# A script for setting the id3 tags of the MP3 files in the RoboDJ
# repository. The data from the database must be dumped into two files:
# entries.txt and songs.txt using the following SQL:
#
# select * from ENTRIES into outfile 'entries.txt';
# select * from SONGS into outfile 'songs.txt';
#
# and this script will operate on those files.
my $usage = "Usage: $0 repository_dir entries.txt songs.txt\n";
my $repodir = shift or die $usage;
my $entfile = shift or die $usage;
my $songfile = shift or die $usage;
# unbuffered output
$| = 1;
if (! -d $repodir) {
die "'$repodir' not a valid repository directory.\n";
}
my %entries;
open(ENTRIES, "$entfile") or die "Can't open '$entfile' for reading: $!\n";
while (<ENTRIES>) {
chomp;
my ($entid, $title, $artist, $source) = split("\t");
$entries{$entid} = [ $title, $artist ];
}
close(ENTRIES);
my $counter = 0;
open(SONGS, "$songfile") or die "Can't open '$songfile' for reading: $!\n";
while (<SONGS>) {
chomp;
my ($songid, $entryid, $position, $title, $location, $duration) =
split("\t");
# escape our arguments
$album = $entries{$entryid}->[0];
$artist = $entries{$entryid}->[1];
# invoke the command
my @cmd = ("id3v2", "--song", "$title",
"--artist", "$artist",
"--album", "$album",
"--track", "$position", "$location");
warn "\nFailed to set tag on $location\n" unless (system(@cmd) == 0);
if ($counter++ % 100 == 99) {
print ".";
}
}
close(SONGS);
print "\nSet ID3 tags on $counter songs.\n";
sub escape {
my ($text) = @_;
$text =~ s:([^A-Za-z0-9]):\\$1:g;
return $text;
}
-20
View File
@@ -1,20 +0,0 @@
#
# $Id: build.properties,v 1.2 2002/11/11 18:23:36 mdb Exp $
#
# Build configuration for the RoboDJ client application.
#
# the URI at which the application is canonically available
application_uri = http://www.samskivert.com/code/robodj
# the jar file keystore
sign.keystore = lib/keystore.dat
# the alias to use when signing the jar files
sign.alias = samskivert
# the keystore password
sign.storepass = monkeybiz
# the host on which the music daemon is running
musicd_host = depravity
-145
View File
@@ -1,145 +0,0 @@
<!-- build configuration -->
<project name="robodj" default="compile" basedir=".">
<!-- import properties -->
<property file="build.properties"/>
<!-- things you may want to change -->
<property name="app.name" value="robodj"/>
<property name="build.compiler" value="jikes"/>
<property name="web.home" value="/export/samskivert/pages/code"/>
<property name="install.dir" value="${web.home}/${app.name}"/>
<property name="narya.home" value="../../work/narya"/>
<!-- things you probably don't want to change -->
<property name="src.dir" value="src/java"/>
<property name="deploy.dir" value="dist"/>
<property name="dist.jar" value="${app.name}.jar"/>
<property name="javadoc.dir" value="${deploy.dir}/docs"/>
<property name="doc.packages" value="robodj.*"/>
<property name="doc.overview" value="robodj/overview.html"/>
<property name="nartool.path" value="${narya.home}/bin"/>
<property name="classes.dir" value="${deploy.dir}/classes"/>
<!-- declare our classpath -->
<path id="classpath">
<fileset dir="lib" includesfile="lib/CLIENT_LIBS"/>
<pathelement location="${classes.dir}"/>
</path>
<!-- generates .java files for all .dobj files -->
<target name="gendobj">
<apply executable="${nartool.path}/gendobj"
failonerror="true" parallel="true">
<srcfile/>
<fileset dir="src/java" includes="**/*.dobj"/>
</apply>
</target>
<!-- generates marshaller and dispatcher classes for all invocation -->
<!-- service declarations -->
<target name="genservice">
<!-- make sure the service class files are all compiled -->
<javac srcdir="src/java" destdir="${classes.dir}"
debug="on" optimize="${build.optimize}" deprecation="on">
<classpath refid="classpath"/>
<include name="**/*Service.java"/>
</javac>
<apply executable="${nartool.path}/genservice"
failonerror="true" parallel="true">
<arg value="--classpath"/>
<arg value="${classes.dir}:lib/narya-distrib.jar:lib/narya-base.jar"/>
<arg value="--sourcedir"/>
<arg value="src/java"/>
<fileset dir="src/java" includes="**/*Service.java"/>
</apply>
</target>
<!-- prepares the application directories -->
<target name="prepare" depends="gendobj">
<mkdir dir="${deploy.dir}"/>
<mkdir dir="${classes.dir}"/>
<mkdir dir="${javadoc.dir}"/>
<!-- copy media and properties into the target directory -->
<copy todir="${classes.dir}">
<fileset dir="${src.dir}" includes="**/*.jpg"/>
<fileset dir="${src.dir}" includes="**/*.png"/>
<fileset dir="${src.dir}" includes="**/*.properties"/>
</copy>
</target>
<!-- cleans out the built application -->
<target name="clean">
<delete dir="${deploy.dir}"/>
</target>
<!-- cleans out the installed application -->
<target name="purge" depends="clean">
<delete dir="${install.dir}"/>
</target>
<!-- build the java class files -->
<target name="compile" depends="prepare">
<javac srcdir="${src.dir}" destdir="${classes.dir}"
debug="on" optimize="off" deprecation="off">
<classpath refid="classpath"/>
</javac>
</target>
<!-- build the javadoc documentation -->
<target name="javadoc" depends="prepare">
<javadoc sourcepath="${src.dir}"
packagenames="${doc.packages}"
windowtitle="${app.name} API"
doctitle="${app.name} API"
overview="${src.dir}/${doc.overview}"
destdir="${javadoc.dir}">
<classpath refid="classpath"/>
<link href="http://www.waywardgeeks.org/code/samskivert/javadoc"/>
<link href="http://java.sun.com/products/jdk/1.3/docs/api"/>
</javadoc>
</target>
<!-- a target for rebuilding everything -->
<target name="all" depends="clean,prepare,compile,javadoc,dist"/>
<!-- builds our distribution files (war and jar) -->
<target name="dist" depends="prepare,compile">
<jar destfile="${deploy.dir}/${dist.jar}"
basedir="${classes.dir}"/>
</target>
<!-- installs the JWS app -->
<target name="install" depends="dist">
<mkdir dir="${install.dir}"/>
<!-- copy the jar files used by the client -->
<copy todir="${install.dir}">
<fileset dir="lib" includesfile="lib/CLIENT_LIBS"/>
<fileset dir="dist" includes="*.jar"/>
</copy>
<!-- sign the jar files -->
<signjar keystore="${sign.keystore}" alias="${sign.alias}"
storepass="${sign.storepass}" lazy="true">
<fileset dir="${install.dir}" includes="*.jar"/>
</signjar>
<!-- copy the jnlp file(s) and associated business into place -->
<filter filtersfile="build.properties"/>
<copy todir="${install.dir}" filtering="true">
<fileset dir="etc" includes="**/*.jnlp"/>
</copy>
<copy todir="${install.dir}">
<fileset dir="etc" includes="**/*.png"/>
</copy>
</target>
<!-- mirrors the files to the production web server -->
<target name="mirror" depends="install">
<echo message="Mirroring files to ${musicd_host}..."/>
<apply executable="rsync" parallel="true">
<fileset dir="${install.dir}" includes="**"/>
<arg line="-av"/>
<srcfile/>
<arg line="${musicd_host}:${install.dir}"/>
</apply>
</target>
</project>
-2
View File
@@ -1,2 +0,0 @@
files
robodj
-26
View File
@@ -1,26 +0,0 @@
robodj (1.2-2) unstable; urgency=low
* Upstream release updated with more features.
-- Michael Bayne <mdb@samskivert.com> Sun, 3 Mar 2002 12:59:12 -0800
robodj (1.2-1) unstable; urgency=low
* New upstream release.
-- Michael Bayne <mdb@samskivert.com> Sat, 2 Mar 2002 22:11:34 -0800
robodj (1.1-1) unstable; urgency=low
* New upstream release.
* Added script for running importer.
* Added defaults file for specifying music daemon host and other
parameters.
-- Michael Bayne <mdb@samskivert.com> Thu, 22 Feb 2002 00:50:00 -0800
robodj (1.0-1) unstable; urgency=low
* Initial Release.
-- Michael Bayne <mdb@samskivert.com> Thu, 21 Feb 2002 23:00:58 -0800
-17
View File
@@ -1,17 +0,0 @@
Source: robodj
Section: contrib/web
Priority: optional
Maintainer: Michael Bayne <mdb@samskivert.com>
Build-Depends: debhelper (>= 3.0.40), ant (>= 1.3-1), j2sdk1.3 (>= 1.3.1-1.1)
Standards-Version: 1.0.0
Package: robodj
Architecture: all
Section: contrib/web
Priority: optional
Depends: java-virtual-machine
Description: Digital music management system
robodj provides tools to convert music from CDs into MP3s and to manage
the resulting music in categories. it stores music metadata in a SQL
database and provides a music server that can be configured a network
enabled client.
-19
View File
@@ -1,19 +0,0 @@
robodj - a digital music management system
Copyright (C) 2002 Michael Bayne
This is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
This is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License with
your Debian GNU/Linux system, in /usr/share/common-licenses/GPL, or with the
lookuplet source package as the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
-1
View File
@@ -1 +0,0 @@
NEWS README
-5
View File
@@ -1,5 +0,0 @@
MUSICD_HOST=depravity
MUSICD_PORT=2500
# The first existing directory is used for JAVA_HOME
JDK_DIRS="/usr/local/jdk1.4 /usr/local/jdk1.3 /usr/lib/j2se/1.3"
-3
View File
@@ -1,3 +0,0 @@
etc/default
usr/bin
usr/share/robodj/lib
-65
View File
@@ -1,65 +0,0 @@
#!/usr/bin/make -f
# debian/rules file for robodj (uses debhelper V3)
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This is the debhelper compatability version to use.
export DH_COMPAT=3
build: build-stamp
build-stamp:
dh_testdir
# call ant to build RoboDJ in the dist directories
ant dist
touch build-stamp
clean:
dh_testdir
dh_testroot
rm -f build-stamp
ant clean
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Install binaries, jars and configuration files
install -m755 bin/rdj* debian/robodj/usr/bin
install -m644 dist/robodj.jar debian/robodj/usr/share/robodj/lib/
install -m644 lib/*.jar debian/robodj/usr/share/robodj/lib/
# Install defaults file
install -m644 debian/robodj.default debian/robodj/etc/default/robodj
# Build architecture-independent files here.
binary-indep: build install
dh_testdir -i
dh_testroot -i
# dh_installdebconf -i
# dh_installdocs -i
# dh_installexamples -i build/conf
# dh_installmenu -i
# dh_installemacsen -i
# dh_installpam -i
# dh_installinit -i
# dh_installcron -i
# dh_installlogrotate -i
# dh_installmanpages -i
# dh_installinfo -i
# dh_undocumented -i jspc.1
dh_installchangelogs -i
# dh_link -i
dh_compress -i
dh_fixperms -i
dh_installdeb -i
# dh_perl -i
dh_gencontrol -i
dh_md5sums -i
dh_builddeb -i
binary: binary-indep
.PHONY: build clean binary-indep binary-arch binary install
-35
View File
@@ -1,35 +0,0 @@
Robo DJ Design
--------------
* Components
- Music database
Schema
OM classes
- Ripper and encoder
Interface with tools (cdparanoia, etc.)
Interface with CDDB
Metadata entry/editing
- Music server
Streams MP3 audio data to player (xmcd?)
...
* Music database:
EID (int) - entry id
PID (int) - parent id
NAME (string) - entry name
LOCATOR (string) - path to data (URL, maybe file: maybe other...)
Album
Name
Artist
Record label
Release date
Genre
Tracks
Name
Index
Import date (date imported into Robo DJ system)
-29
View File
@@ -1,29 +0,0 @@
RoboDJ Notes
------------
- Rewrite music daemon in Java, have the clients communicate with it using
a more robust protocol (maybe Narya) so that they can be informed when
shared state (the current track, etc.) changes
- Provide a protocol for uploading mp3 files via the music server to avoid
having to do it by hand
- Use Java code to handle ID3 reading and updating
- Write a tool to import existing MP3 files into the system
- Play a sound when the ripping process is complete (or when an error
occurs) because the user may be off doing something in another window
- Have musicd manage the playlist hierarchically so that if we add a whole
CD to the playlist, we can remove it in the same way. Also pass the
metadata (entryid, songid) to the musicd as well so that we don't have
to reverse engineer things when we're displaying the contents of the
playlist.
- Restructure ripping process so that the panel code drives the ripping of
each track which would allow it to respond to ripping failures and
provide the ability to retry or ignore a track that fails to rip.
- Add check to see if a disc is already in the repository and offer to
re-rip it.
-40
View File
@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for RoboDJ music chooser -->
<!-- If you're seeing this in your web browser, you probably need to
download and install the Sun JRE 1.4 and/or Java Web Start from
http://java.sun.com/j2se/ -->
<jnlp spec="1.0+" codebase="@application_uri@/" href="chooser.jnlp">
<information>
<title>RoboDJ Chooser</title>
<vendor>Seuss and Asseusciates</vendor>
<homepage href="index.html"/>
<icon href="icon.png"/>
<description kind="short">
Music choosing fun for the whole family!
</description>
<description>
Provides a browser for the RoboDJ music repository and an interface
by which that music can be queued up for playing on the music
server.
</description>
<offline-allowed/>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.4+" href="http://java.sun.com/products/autodl/j2se"/>
<jar href="robodj.jar"/>
<jar href="commons-io.jar"/>
<jar href="commons-lang.jar"/>
<jar href="mysql-connector-java-3.0.11-stable-bin.jar"/>
<jar href="samskivert.jar"/>
<jar href="narya-base.jar"/>
<jar href="narya-distrib.jar"/>
<property name="musicd_host" value="@musicd_host@"/>
</resources>
<application-desc main-class="robodj.chooser.Chooser"/>
</jnlp>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

-6
View File
@@ -1,6 +0,0 @@
commons-io.jar
commons-lang.jar
mysql-connector-java-3.0.11-stable-bin.jar
samskivert.jar
narya-base.jar
narya-distrib.jar
-13
View File
@@ -1,13 +0,0 @@
Various third party libraries are needed by RoboDJ.
- Jakarta Commons Collections (org.apache.commons.*)
http://jakarta.apache.org/commons
- Narya (com.threerings.narya.*)
http://www.threerings.net/code/narya/
- samskivert (com.samskivert.*)
http://www.samskivert.com/code/samskivert/
- The MySQL JDBC driver (though others might work as well)
http://dev.mysql.com/downloads/connector/j/3.1.html
Binary file not shown.
-38
View File
@@ -1,38 +0,0 @@
//
// $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);
}
}
@@ -1,13 +0,0 @@
//
// $Id: Version.java,v 1.2 2002/11/11 17:33:43 mdb Exp $
package robodj;
/**
* Used to report version numbers in the client.
*/
public class Version
{
/** The application release version. */
public static String RELEASE_VERSION = "1.3";
}
@@ -1,59 +0,0 @@
//
// $Id: BrowsePanel.java,v 1.6 2004/01/26 16:33:40 mdb Exp $
package robodj.chooser;
import java.awt.BorderLayout;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import com.samskivert.swing.GroupLayout;
import com.samskivert.util.CollectionUtil;
import robodj.repository.*;
public class BrowsePanel extends JPanel
{
public BrowsePanel ()
{
setLayout(new BorderLayout(5, 5));
// obtain our categories
ArrayList cats = new ArrayList();
CollectionUtil.addAll(cats, Chooser.model.getCategories());
// add an "Uncategorized" category
cats.add(new Category(-1, "Uncategorized"));
final JList clist = new JList(cats.toArray());
clist.getSelectionModel().setSelectionMode(
ListSelectionModel.SINGLE_SELECTION);
ListSelectionListener lsl = new ListSelectionListener() {
public void valueChanged (ListSelectionEvent lse) {
Category cat = (Category)clist.getSelectedValue();
if (cat != null) {
_hlabel.setText(cat.name);
_category.setCategory(cat.categoryid);
}
}
};
clist.getSelectionModel().addListSelectionListener(lsl);
add(new JScrollPane(clist), BorderLayout.WEST);
JPanel main = GroupLayout.makeVStretchBox(3);
add(main, BorderLayout.CENTER);
JPanel header = GroupLayout.makeButtonBox(GroupLayout.CENTER);
header.add(_hlabel = new JLabel());
_hlabel.setFont(getFont().deriveFont(18f));
main.add(header, GroupLayout.FIXED);
main.add(_category = new CategoryEntryList(-1));
clist.setSelectedIndex(cats.size()-1);
}
protected CategoryEntryList _category;
protected JLabel _hlabel;
}
@@ -1,49 +0,0 @@
//
// $Id: CategoryEntryList.java,v 1.3 2004/01/26 16:10:55 mdb Exp $
package robodj.chooser;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.Controller;
import robodj.repository.Entry;
public class CategoryEntryList extends EntryList
{
/**
* Constructs an entry list for entries in a particular category.
*/
public CategoryEntryList (int categoryId)
{
setCategory(categoryId);
}
/**
* Updates our category.
*/
public void setCategory (int categoryId)
{
if (categoryId != _categoryId) {
_categoryId = categoryId;
Controller.postAction(this, "refresh");
}
}
// documentation inherited
protected Controller createController ()
{
return new EntryController(this) {
public Entry[] readEntries () throws PersistenceException {
return Chooser.model.getEntries(_categoryId);
}
};
}
protected String getEmptyString ()
{
return "No entries in this category.";
}
/** The unique identifier of the category we are displaying. */
protected int _categoryId;
}
@@ -1,117 +0,0 @@
//
// $Id: Chooser.java,v 1.14 2004/01/26 16:33:40 mdb Exp $
package robodj.chooser;
import java.util.Properties;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.StaticConnectionProvider;
import com.samskivert.util.StringUtil;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.util.ConfigUtil;
import com.samskivert.util.PropertiesUtil;
import com.samskivert.util.RunAnywhere;
import robodj.Log;
import robodj.repository.Model;
import robodj.repository.Repository;
import robodj.util.ErrorUtil;
import robodj.util.RDJPrefs;
import robodj.util.RDJPrefsPanel;
/**
* The chooser is the GUI-based application for browsing the music
* collection and managing the playlist.
*/
public class Chooser extends DJClient
{
public static Repository repository;
public static Model model;
public static ChooserFrame frame;
public void init ()
{
boolean error = false;
// try {
// UIManager.setLookAndFeel(
// RunAnywhere.isLinux() ?
// "com.sun.java.swing.plaf.gtk.GTKLookAndFeel" :
// UIManager.getSystemLookAndFeelClassName());
// } catch (Exception e) {
// Log.info("Failed to set GTK look and feel: " + e);
// }
// loop until the user provides us with a configuration that works
// or requests to exit
for (int ii = 0; ii < 100; ii++) {
String repodir = RDJPrefs.getRepositoryDirectory();
if (StringUtil.blank(repodir) || ii > 0) {
// display the initial configuration wizard if we are not
// yet properly configured
RDJPrefsPanel.display(true);
}
// create an interface to the database repository
try {
StaticConnectionProvider scp =
new StaticConnectionProvider(RDJPrefs.getJDBCConfig());
repository = new Repository(scp);
model = new Model(repository);
} catch (PersistenceException pe) {
String errmsg = "Unable to communicate with database:";
if (ErrorUtil.reportError(errmsg, pe)) {
System.exit(-1);
}
continue;
}
if (!connectToServer()) {
continue;
}
break;
}
}
// documentation inherited from interface
public void invokeLater (Runnable run)
{
SwingUtilities.invokeLater(run);
}
protected void didInit ()
{
super.didInit();
displayInterface();
}
protected void displayInterface ()
{
if (frame == null) {
// create our primary user interface frame, center the frame
// in the screen and show it
frame = new ChooserFrame();
frame.setSize(660, frame.getToolkit().getScreenSize().height - 60);
SwingUtil.centerWindow(frame);
frame.setVisible(true);
} else {
frame.toFront();
}
}
public static void main (String[] args)
{
Chooser chooser = new Chooser();
chooser.init();
}
}
@@ -1,50 +0,0 @@
//
// $Id: ChooserController.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
package robodj.chooser;
import java.awt.event.ActionEvent;
import com.samskivert.swing.Controller;
import robodj.Log;
/**
* Handles top-level chooser UI commands.
*/
public class ChooserController extends Controller
{
public ChooserController ()
{
}
// documentation inherited
public boolean handleAction (ActionEvent event)
{
String cmd = event.getActionCommand();
if (cmd.equals("exit")) {
Chooser.exit();
} else if (cmd.equals("skip")) {
Chooser.djobj.skip();
} else if (cmd.equals("back")) {
Chooser.djobj.back();
} else if (cmd.equals("pause")) {
Chooser.djobj.pause();
} else if (cmd.equals("play")) {
Chooser.djobj.play();
} else if (cmd.equals("stop")) {
Chooser.djobj.stop();
} else {
Log.warning("Unknown action event: " + cmd);
return false;
}
return true;
}
}
@@ -1,227 +0,0 @@
//
// $Id: ChooserFrame.java,v 1.13 2004/01/26 16:35:27 mdb Exp $
package robodj.chooser;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
import com.samskivert.swing.*;
import com.samskivert.swing.util.*;
import com.samskivert.util.StringUtil;
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.presents.dobj.AttributeChangedEvent;
import robodj.Log;
import robodj.Version;
import robodj.repository.*;
import robodj.util.ButtonUtil;
import robodj.util.FancyPanel;
import robodj.util.RDJPrefs;
public class ChooserFrame extends JFrame
implements ControllerProvider, AttributeChangeListener
{
public ChooserFrame ()
{
super("RoboDJ Chooser " + Version.RELEASE_VERSION);
// quit gracefully if we're closed
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing (WindowEvent e) {
Chooser.exit();
}
});
// we create a top-level panel to manage everything
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
JPanel top = new FancyPanel(gl, ButtonUtil.getImage(BACKGROUND_PATH));
top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
// the top of the UI is the browser and the playlist manager
JTabbedPane tpane = new JTabbedPane();
tpane.setBackground(BGCOLOR);
PlaylistPanel ppanel = new PlaylistPanel();
String tip = "View and manipulate the playlist.";
tpane.addTab("Playlist", null, ppanel, tip);
BrowsePanel bpanel = new BrowsePanel();
tip = "Browse and select tunes to play.";
tpane.addTab("Browse", null, bpanel, tip);
SearchPanel spanel = new SearchPanel();
tip = "Search titles and artists.";
tpane.addTab("Search", null, spanel, tip);
top.add(tpane);
// the bottom is the control bar
GroupLayout bgl = new HGroupLayout(GroupLayout.NONE);
bgl.setJustification(GroupLayout.RIGHT);
JPanel cbar = new JPanel(bgl);
// create a label and text field where the chooser user can
// identify themselves
cbar.add(new JLabel("Initials:"));
cbar.add(_userField = new JTextField());
Dimension ups = _userField.getPreferredSize();
ups.width = 35;
_userField.setPreferredSize(ups);
cbar.add(new Spacer(100, 10));
// enforce a maximum of 3 letters in initials
SwingUtil.setDocumentHelpers(
_userField, new SwingUtil.DocumentValidator() {
public boolean isValid (String text) {
return (text.length() <= 3);
}
}, null);
// display any previously configured initials
_userField.setText(RDJPrefs.getUser());
// add some fake control buttons for now
cbar.add(ButtonUtil.createControlButton(
BACK_TIP, "back", BACK_ICON_PATH, true));
_stop = ButtonUtil.createControlButton(
STOP_TIP, "stop", STOP_ICON_PATH, true);
cbar.add(_stop);
_pauseIcon = ButtonUtil.getIcon(PAUSE_ICON_PATH);
_playIcon = ButtonUtil.getIcon(PLAY_ICON_PATH);
_pause = ButtonUtil.createControlButton(
"", "pause", _pauseIcon, true);
cbar.add(_pause);
cbar.add(ButtonUtil.createControlButton(
SKIP_TIP, "skip", SKIP_ICON_PATH, true));
cbar.add(new Spacer(50, 10));
cbar.add(ButtonUtil.createControlButton(
EXIT_TIP, "exit", EXIT_ICON_PATH, true));
// stick it into the frame
top.add(cbar, GroupLayout.FIXED);
// now add our top-level panel (we'd not use this if we could set
// a border on the content pane returned by the frame... alas)
getContentPane().add(top, BorderLayout.CENTER);
SwingUtil.applyToHierarchy(top, new SwingUtil.ComponentOp() {
public void apply (Component comp) {
if (comp instanceof JPanel || comp instanceof JButton) {
((JComponent) comp).setOpaque(false);
}
}
});
// listen for pause and stop and whatnot
Chooser.djobj.addListener(this);
updateButtons();
// create our controller
_controller = new ChooserController();
}
// documentation inherited from interface
public Controller getController ()
{
return _controller;
}
/**
* Returns the string currently entered into the "user" field.
*/
public String getUser (boolean showError)
{
String user = _userField.getText();
// if they haven't supplied a user, complain
if (StringUtil.blank(user)) {
if (!showError) {
return null;
}
String errmsg = "The feature you have requested requires " +
"that you identify yourself by entering your initials in " +
"the 'Initials' box at the bottom of the window.";
JOptionPane.showMessageDialog(this, errmsg, "Initials required",
JOptionPane.ERROR_MESSAGE);
return null;
}
// if they typed in mixed or upper case, lower it for them
user = user.toLowerCase();
if (!user.equals(_userField.getText())) {
_userField.setText(user);
}
// make sure we've saved these initials values
RDJPrefs.config.setValue(RDJPrefs.USER_KEY, user);
return user;
}
// documentation inherited from interface
public void attributeChanged (AttributeChangedEvent event)
{
updateButtons();
}
protected void updateButtons ()
{
if (Chooser.djobj.playing == -1 || Chooser.djobj.paused) {
_pause.setToolTipText(PLAY_TIP);
_pause.setActionCommand("play");
_pause.setIcon(_playIcon);
} else {
_pause.setToolTipText(PAUSE_TIP);
_pause.setActionCommand("pause");
_pause.setIcon(_pauseIcon);
}
_stop.setEnabled(Chooser.djobj.playing != -1);
_pause.setEnabled(Chooser.djobj.playlist != null);
}
/** Our top-level controller. */
protected Controller _controller;
/** A field where the user can identify themselves. */
protected JTextField _userField;
/** A reference to the play/pause button. */
protected JButton _pause;
/** A reference to the stop button. */
protected JButton _stop;
// used when toggling between play and pause
protected ImageIcon _playIcon;
protected ImageIcon _pauseIcon;
// icon paths
protected static final String ICON_ROOT = "/robodj/chooser/images/";
protected static final String PLAY_ICON_PATH = ICON_ROOT + "play.png";
protected static final String PAUSE_ICON_PATH = ICON_ROOT + "pause.png";
protected static final String STOP_ICON_PATH = ICON_ROOT + "stop.png";
protected static final String SKIP_ICON_PATH = ICON_ROOT + "skip.png";
protected static final String BACK_ICON_PATH = ICON_ROOT + "back.png";
protected static final String EXIT_ICON_PATH = ICON_ROOT + "exit.png";
protected static final String BACKGROUND_PATH =
ICON_ROOT + "background.png";
// button tips
protected static final String PLAY_TIP = "Play";
protected static final String PAUSE_TIP =
"Pause the currently playing song";
protected static final String STOP_TIP = "Stop the currently playing song";
protected static final String SKIP_TIP = "Skip to the next song";
protected static final String BACK_TIP = "Skip to the previous song";
protected static final String EXIT_TIP = "Exit";
// our common background color
protected static final Color BGCOLOR = new Color(0x9999CC);
}
@@ -1,155 +0,0 @@
//
// $Id$
package robodj.chooser;
import java.io.IOException;
import com.samskivert.util.StringUtil;
import com.threerings.util.Name;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.ClientObserver;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.ObjectAccessException;
import com.threerings.presents.dobj.Subscriber;
import com.threerings.presents.net.UsernamePasswordCreds;
import robodj.client.DJService;
import robodj.data.DJObject;
import robodj.util.ErrorUtil;
import robodj.util.RDJPrefs;
import robodj.util.RDJPrefsPanel;
/**
* Handles the common client business for RoboDJ.
*/
public abstract class DJClient
implements Client.Invoker, ClientObserver, Subscriber
{
public static Client client;
public static DJObject djobj;
/**
* Creates our {@link Client} instance and connects to the RoboDJ
* server.
*
* @return true if the client was created successfully and the
* connection process was initiated, false if it was not due to
* missing or bogus configuration.
*/
public boolean connectToServer ()
{
try {
String host = RDJPrefs.getMusicDaemonHost();
if (StringUtil.blank(host)) {
throw new IOException(
"No music server host specified in configuration.");
}
// establish a connection with the music server
Name name = new Name(RDJPrefs.getUser());
client = new Client(new UsernamePasswordCreds(name, ""), this);
client.addClientObserver(this);
client.setServer(host, Client.DEFAULT_SERVER_PORT);
client.logon();
return true;
} catch (IOException ioe) {
String errmsg = "Unable to communicate with music " +
"server on host '" + RDJPrefs.getMusicDaemonHost() + "' ";
if (ErrorUtil.reportError(errmsg, ioe)) {
System.exit(-1);
}
return false;
}
}
// documentation inherited from interface
public void clientDidLogon (Client lclient)
{
// subscribe to our DJObject
DJService djsvc = (DJService)client.requireService(DJService.class);
djsvc.getDJOid(client, new DJService.ResultListener() {
public void requestProcessed (Object result) {
int djoid = ((Integer)result).intValue();
client.getDObjectManager().subscribeToObject(
djoid, DJClient.this);
}
public void requestFailed (String cause) {
ErrorUtil.reportError("Failed to fetch DJ oid: " + cause, null);
System.exit(-1);
}
});
}
// documentation inherited from interface
public void clientObjectDidChange (Client client)
{
}
// documentation inherited from interface
public void clientDidLogoff (Client client)
{
System.exit(-1);
}
// documentation inherited from interface
public void clientFailedToLogon (Client lclient, Exception cause)
{
if (ErrorUtil.reportError("Failed to connect to server", cause)) {
System.exit(-1);
} else {
Thread t = new Thread() {
public void run () {
RDJPrefsPanel.display(true);
client.setServer(RDJPrefs.getMusicDaemonHost(),
Client.DEFAULT_SERVER_PORT);
client.logon();
}
};
t.start();
}
}
// documentation inherited from interface
public void clientConnectionFailed (Client client, Exception cause)
{
ErrorUtil.reportError("Lost connection to server", cause);
System.exit(-1);
}
// documentation inherited from interface
public boolean clientWillLogoff (Client client)
{
return true;
}
// documentation inherited from interface
public void objectAvailable (DObject object)
{
djobj = (DJObject)object;
didInit();
}
// documentation inherited from interface
public void requestFailed (int oid, ObjectAccessException cause)
{
ErrorUtil.reportError("Failed to fetch DJ object", cause);
System.exit(-1);
}
/**
* Called when we have successfully connected to the server and
* subscribed to our {@link DJObject}.
*/
protected void didInit ()
{
}
public static void exit ()
{
client.logoff(false);
}
}
@@ -1,116 +0,0 @@
//
// $Id: EditDialog.java,v 1.3 2001/09/21 03:09:01 mdb Exp $
package robodj.chooser;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.*;
import com.samskivert.swing.util.*;
import robodj.Log;
import robodj.repository.Entry;
import robodj.repository.EntryEditor;
public class EditDialog
extends JDialog
implements TaskObserver, ActionListener
{
public EditDialog (Entry entry)
{
setTitle("Edit " + entry.title);
// keep this around for later
_entry = entry;
// we create a top-level panel to manage everything
JPanel top = new JPanel();
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
top.setLayout(gl);
// give ourselves a wee bit of a border
top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
// create our entry editor
_editor = new EntryEditor(Chooser.model, entry);
top.add(_editor);
// create some control buttons
gl = new HGroupLayout(GroupLayout.NONE);
gl.setJustification(GroupLayout.RIGHT);
JPanel btnPanel = new JPanel(gl);
btnPanel.add(createControlButton("Update", "update"));
btnPanel.add(createControlButton("Revert", "revert"));
btnPanel.add(createControlButton("Cancel", "cancel"));
top.add(btnPanel, GroupLayout.FIXED);
getContentPane().add(top, BorderLayout.CENTER);
}
public void actionPerformed (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals("update")) {
// flush the edits to the entry
_editor.applyToEntry();
// do the update in a separate task
TaskMaster.invokeMethodTask("updateEntry", this, this);
} else if (cmd.equals("revert")) {
_editor.reset();
} else if (cmd.equals("cancel")) {
// get the hell out of dodge
dispose();
} else {
System.out.println("Unknown action event: " + cmd);
}
}
/**
* Updates the entry in the repository.
*/
public void updateEntry ()
throws PersistenceException
{
Chooser.model.updateEntry(_entry);
}
public void taskCompleted (String name, Object result)
{
if (name.equals("updateEntry")) {
// we're done updating, we can go away now
dispose();
}
}
public void taskFailed (String name, Throwable exception)
{
String msg;
if (Exception.class.equals(exception.getClass())) {
msg = exception.getMessage();
} else {
msg = exception.toString();
}
JOptionPane.showMessageDialog(this, msg, "Error",
JOptionPane.ERROR_MESSAGE);
Log.logStackTrace(exception);
}
protected JButton createControlButton (String label, String action)
{
JButton btn = new JButton(label);
btn.setActionCommand(action);
btn.addActionListener(this);
return btn;
}
protected Entry _entry;
protected EntryEditor _editor;
}
@@ -1,186 +0,0 @@
//
// $Id: EntryController.java,v 1.3 2004/01/26 16:10:55 mdb Exp $
package robodj.chooser;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.swing.util.TaskMaster;
import com.samskivert.util.ArrayUtil;
import robodj.Log;
import robodj.data.PlaylistEntry;
import robodj.repository.Entry;
import robodj.repository.Song;
/**
* Handles default entry list behavior.
*/
public abstract class EntryController extends ItemController
implements AncestorListener
{
public EntryController (EntryList list)
{
super(list);
_list = list;
_list.addAncestorListener(this);
}
/**
* Reads the entries from the database.
*/
public void readSongs ()
throws PersistenceException
{
Chooser.repository.populateSongs(_entry);
}
/**
* Reads the entries from the database and plays them all.
*/
public void readAndPlay ()
throws PersistenceException
{
Chooser.repository.populateSongs(_entry);
}
/**
* Updates the category for the displayed entry.
*/
public void recategorizeEntry ()
throws PersistenceException
{
Chooser.model.recategorize(_entry, _newcatid);
}
// documentation inherited from interface
public void taskCompleted (String name, Object result)
{
if (name.equals("readEntries")) {
// the result should be an array of entry objects with which
// we can populate our button list
_entries = (Entry[])result;
_list.populateEntries(_entries);
} else if (name.equals("readAndPlay")) {
appendToPlaylist(_entry.songs);
} else if (name.equals("readSongs")) {
_list.populateSong(_entry);
} else {
super.taskCompleted(name, result);
}
}
/**
* Reads the entries from the database. This will be called on a
* separate thread and should be prepared to be called repeatedly
* without undue overhead. When the user browses into a song and back
* up again, this method is called to repopulate the entries.
*/
public abstract Entry[] readEntries ()
throws PersistenceException;
// documentation inherited from interface
public boolean handleAction (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals(EntryItem.BROWSE)) {
_entry = EntryItem.getEntry(e.getSource());
// start up the task that reads this CDs songs from the database
TaskMaster.invokeMethodTask("readSongs", this, this);
} else if (cmd.equals(EntryItem.PLAY)) {
_entry = EntryItem.getEntry(e.getSource());
// start up the task that reads this CDs songs from the database
TaskMaster.invokeMethodTask("readAndPlay", this, this);
} else if (cmd.equals(SongItem.PLAY)) {
Song song = SongItem.getSong(e.getSource());
appendToPlaylist(new Song[] { song });
} else if (cmd.equals("refresh")) {
// re-read the category
TaskMaster.invokeMethodTask("readEntries", this, this);
} else if (cmd.equals("edit")) {
EditDialog dialog = new EditDialog(_entry);
dialog.setSize(400, 400);
SwingUtil.centerWindow(dialog);
dialog.show();
} else if (cmd.equals("categorize")) {
JComboBox cb = (JComboBox)e.getSource();
String catname = (String)cb.getSelectedItem();
_newcatid = Chooser.model.getCategoryId(catname);
// do the recategorization in a separate task
TaskMaster.invokeMethodTask("recategorizeEntry", this, this);
} else {
return super.handleAction(e);
}
return true;
}
// documentation inherited from interface
public void ancestorAdded (AncestorEvent e)
{
// stick a "loading" label in the list to let the user know
// what's up
_list._bpanel.add(new JLabel("Loading..."));
// we need to revalidate the component because we added a child
_list.revalidate();
_list.repaint();
// start up the task that reads the CD info from the database
TaskMaster.invokeMethodTask("readEntries", this, this);
}
// documentation inherited from interface
public void ancestorRemoved (AncestorEvent e)
{
// clear out our entry ui elements
_list._bpanel.removeAll();
}
// documentation inherited from interface
public void ancestorMoved (AncestorEvent e)
{
// nothing doing
}
protected void appendToPlaylist (Song[] songs)
{
PlaylistEntry[] plist = Chooser.djobj.playlist;
if (plist == null) {
plist = new PlaylistEntry[0];
}
for (int i = 0; i < songs.length; i++) {
if (songs[i].isHated()) {
continue;
}
PlaylistEntry entry = new PlaylistEntry(
songs[i].entryid, songs[i].songid, songs[i].title);
plist = (PlaylistEntry[])ArrayUtil.append(plist, entry);
}
Chooser.djobj.setPlaylist(plist);
}
protected EntryList _list;
protected Entry[] _entries;
protected Entry _entry;
protected int _newcatid;
}
@@ -1,72 +0,0 @@
//
// $Id: EntryItem.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
package robodj.chooser;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import com.samskivert.swing.HGroupLayout;
import robodj.repository.Entry;
import robodj.util.ButtonUtil;
/**
* Displays an entry in the browser.
*/
public class EntryItem extends Item
{
public static final String BROWSE = "entry:browse";
public static final String PLAY = "entry:play";
public EntryItem (Entry entry)
{
_entry = entry;
// set up our layout manager
HGroupLayout gl = new HGroupLayout(HGroupLayout.NONE);
gl.setOffAxisPolicy(HGroupLayout.STRETCH);
gl.setJustification(HGroupLayout.LEFT);
setLayout(gl);
// create a browse and a play button
JButton button;
// add a browse button
button = ButtonUtil.createControlButton(
BROWSE_ENTRY_TIP, BROWSE, _browseIcon, true);
button.putClientProperty(ENTRY_PROP, entry);
add(button, HGroupLayout.FIXED);
// add a play all button
button = ButtonUtil.createControlButton(
PLAY_ENTRY_TIP, PLAY, _playIcon, true);
button.putClientProperty(ENTRY_PROP, entry);
add(button, HGroupLayout.FIXED);
// add the entry title
JLabel entryLabel = new JLabel(entry.title);
entryLabel.setFont(_nameFont);
entryLabel.setToolTipText(entry.title + " (" + entry.entryid + ")");
add(entryLabel);
}
public static Entry getEntry (Object source)
{
return (Entry)((JButton)source).getClientProperty(ENTRY_PROP);
}
protected Entry _entry;
protected static final String ENTRY_PROP = "entry";
protected static final String BROWSE_ENTRY_TIP =
"Browse the songs in this album";
protected static final String PLAY_ENTRY_TIP =
"Append this album to the playlist";
protected static ImageIcon _browseIcon =
ButtonUtil.getIcon(ICON_ROOT + "browse.png");
}
@@ -1,204 +0,0 @@
//
// $Id: EntryList.java,v 1.15 2004/01/26 16:33:40 mdb Exp $
package robodj.chooser;
import java.awt.Font;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.*;
import com.samskivert.swing.util.*;
import robodj.Log;
import robodj.repository.*;
import robodj.util.ButtonUtil;
public abstract class EntryList extends JSplitPane
implements ControllerProvider
{
public EntryList ()
{
super(JSplitPane.VERTICAL_SPLIT);
setLeftComponent(new JScrollPane(_bpanel = createPanel()));
setRightComponent(new JScrollPane(_epanel = createPanel()));
// use a special font for our name buttons
_titleFont = new Font("Helvetica", Font.BOLD, 14);
// create our controller
_controller = createController();
}
// documentation inherited
public void doLayout ()
{
super.doLayout();
// we only want to do this once so as not to mess with subsequent
// adjustments by the user
if (!_adjusted) {
setDividerLocation(0.5f);
_adjusted = true;
}
}
/**
* Creates a panel configured for displaying entries or songs.
*/
protected JPanel createPanel ()
{
GroupLayout gl = new VGroupLayout(GroupLayout.NONE);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
gl.setJustification(GroupLayout.TOP);
gl.setGap(2);
JPanel panel = new ScrollablePanel() {
// make the playlist fit the width of the scrolling viewport
public boolean getScrollableTracksViewportWidth () {
return true;
}
};
panel.setLayout(gl);
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
return panel;
}
public Controller getController ()
{
return _controller;
}
/** Creates the controller for this entry list. */
protected abstract Controller createController ();
/** The string to display when there are no matching results. */
protected abstract String getEmptyString ();
/**
* Creates the proper buttons, etc. for each entry.
*/
protected void populateEntries (Entry[] entries)
{
// clear out any existing children
_bpanel.removeAll();
// sort our entries
Comparator ecomp = new Comparator() {
public int compare (Object o1, Object o2) {
Entry e1 = (Entry)o1, e2 = (Entry)o2;
int rv = e1.artist.compareTo(e2.artist);
return rv == 0 ? e1.title.compareTo(e2.title) : rv;
}
public boolean equals (Object o1) {
return o1.equals(this);
}
};
Arrays.sort(entries, ecomp);
// and add buttons for every entry
String artist = null;
for (int i = 0; i < entries.length; i++) {
if (!entries[i].artist.equals(artist)) {
artist = entries[i].artist;
JLabel label = new JLabel(entries[i].artist);
_bpanel.add(label);
}
// create an entry item for this entry
_bpanel.add(new EntryItem(entries[i]));
}
// if there were no entries, stick a label in to that effect
if (entries.length == 0) {
_bpanel.add(new JLabel(getEmptyString()));
}
// reset our scroll position
clearScrollPosition((JScrollPane)getLeftComponent());
// we've removed and added components so we need to revalidate
SwingUtil.refresh(_bpanel);
}
protected void populateSong (Entry entry)
{
// clear out any existing children
_epanel.removeAll();
GroupLayout gl = new HGroupLayout(HGroupLayout.STRETCH);
gl.setJustification(GroupLayout.LEFT);
JPanel header = new JPanel(gl);
// add the album title
JLabel label = new JLabel(entry.title);
label.setToolTipText(entry.title);
label.setFont(_titleFont);
header.add(label);
// create an edit button
JButton ebtn = ButtonUtil.createControlButton(
EDIT_TIP, "edit", ButtonUtil.getIcon(EDIT_ICON_PATH), true);
header.add(ebtn, GroupLayout.FIXED);
// add a combo box for categorizing
JComboBox catcombo =
new JComboBox(ModelUtil.catBoxNames(Chooser.model));
header.add(catcombo, GroupLayout.FIXED);
// configure the combo box
catcombo.addActionListener(Controller.DISPATCHER);
catcombo.setActionCommand("categorize");
int catid = Chooser.model.getCategory(entry.entryid);
int catidx = ModelUtil.getCategoryIndex(Chooser.model, catid);
catcombo.setSelectedIndex(catidx+1);
_epanel.add(header, GroupLayout.FIXED);
// sort the songs by position
Comparator scomp = new Comparator() {
public int compare (Object o1, Object o2) {
Song s1 = (Song)o1, s2 = (Song)o2;
return s1.position - s2.position;
}
public boolean equals (Object o1) {
return o1.equals(this);
}
};
Arrays.sort(entry.songs, scomp);
// and add buttons for every song
for (int i = 0; i < entry.songs.length; i++) {
_epanel.add(new SongItem(entry.songs[i], SongItem.BROWSER));
}
// we've removed and added components so we need to revalidate
SwingUtil.refresh(_epanel);
}
protected void clearScrollPosition (JScrollPane pane)
{
BoundedRangeModel model = pane.getVerticalScrollBar().getModel();
model.setValue(model.getMinimum());
}
protected Controller _controller;
protected JPanel _bpanel;
protected JPanel _epanel;
protected boolean _adjusted;
protected Font _titleFont;
protected static final String UP_TIP =
"Back up to albums listing";
protected static final String EDIT_TIP =
"Edit the album information";
protected static final String ICON_ROOT = "/robodj/chooser/images/";
protected static final String UP_ICON_PATH = ICON_ROOT + "up.png";
protected static final String EDIT_ICON_PATH = ICON_ROOT + "edit.png";
}
@@ -1,39 +0,0 @@
//
// $Id: Item.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
package robodj.chooser;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import com.samskivert.swing.util.SwingUtil;
import robodj.util.ButtonUtil;
/**
* The base class for items displayed in an entry list or playlist.
*/
public class Item extends JPanel
{
// documentation inherited
protected void paintChildren (Graphics g)
{
Graphics2D gfx = (Graphics2D)g;
Object key = SwingUtil.activateAntiAliasing(gfx);
super.paintChildren(g);
SwingUtil.restoreAntiAliasing(gfx, key);
}
protected static Font _nameFont = new Font("Dialog", Font.PLAIN, 12);
protected static Font _hasVotesFont =
new Font("Dialog", Font.ITALIC, 12);
protected static final String ICON_ROOT = "/robodj/chooser/images/";
protected static ImageIcon _playIcon =
ButtonUtil.getIcon(ICON_ROOT + "play.png");
}
@@ -1,94 +0,0 @@
//
// $Id: ItemController.java,v 1.2 2003/10/10 21:31:57 mdb Exp $
package robodj.chooser;
import java.awt.event.ActionEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.Controller;
import com.samskivert.swing.util.TaskMaster;
import com.samskivert.swing.util.TaskObserver;
import robodj.Log;
import robodj.repository.Song;
import robodj.util.ErrorUtil;
/**
* Handles standard commands when displaying lists of items.
*/
public abstract class ItemController extends Controller
implements TaskObserver
{
public ItemController (JComponent panel)
{
_panel = panel;
}
// documentation inherited from interface
public boolean handleAction (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals(SongItem.TOGGLE_VOTE)) {
JButton button = (JButton)e.getSource();
SongItem item = (SongItem)button.getParent();
_song = item.getSong();
String who = Chooser.frame.getUser(true);
switch (_song.hasVoted(who)) {
case -1: _song.addVote(who, true); break;
case 1: _song.clearVote(who); break;
default:
case 0: _song.addVote(who, false); break;
}
item.update();
TaskMaster.invokeMethodTask("updateSong", this, this);
} else {
Log.warning("Unknown action event: " + cmd);
return false;
}
return true;
}
/**
* Updates the song referenced by {@link #_song} in the repository.
*/
public void updateSong ()
{
if (_song != null) {
try {
Chooser.repository.updateSong(_song);
} catch (PersistenceException pe) {
ErrorUtil.reportError(
"Failure updating song '" + _song + "'", pe);
}
}
}
// documentation inherited from interface
public void taskCompleted (String name, Object result)
{
}
// documentation inherited from interface
public void taskFailed (String name, Throwable exception)
{
String msg;
if (Exception.class.equals(exception.getClass())) {
msg = exception.getMessage();
} else {
msg = exception.toString();
}
JOptionPane.showMessageDialog(_panel, msg, "Error",
JOptionPane.ERROR_MESSAGE);
Log.logStackTrace(exception);
}
protected JComponent _panel;
protected Song _song;
}
@@ -1,174 +0,0 @@
//
// $Id: PlaylistController.java,v 1.3 2004/02/24 12:40:24 mdb Exp $
package robodj.chooser;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Iterator;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import com.samskivert.io.PersistenceException;
import com.samskivert.util.StringUtil;
import com.samskivert.swing.util.SwingUtil;
import com.samskivert.swing.util.TaskAdapter;
import com.samskivert.swing.util.TaskMaster;
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.presents.dobj.AttributeChangedEvent;
import robodj.Log;
import robodj.data.DJObject;
import robodj.data.PlaylistEntry;
import robodj.repository.Entry;
import robodj.repository.Song;
/**
* Handles playlist UI commands.
*/
public class PlaylistController extends ItemController
implements AttributeChangeListener
{
public PlaylistController (PlaylistPanel panel)
{
super(panel);
_panel = panel;
// listen to the DJ object
Chooser.djobj.addListener(this);
}
public void wasAdded ()
{
super.wasAdded();
// start up the task that reads the CD info from the database
TaskMaster.invokeMethodTask("readPlaylist", this, this);
}
// documentation inherited
public boolean handleAction (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals(PlaylistPanel.CLEAR)) {
Chooser.djobj.clear();
} else if (cmd.equals(SongItem.SKIP_TO)) {
JButton button = (JButton)e.getSource();
SongItem item = (SongItem)button.getParent();
Chooser.djobj.play(((Integer)item.extra).intValue());
} else if (cmd.equals(SongItem.REMOVE)) {
JButton button = (JButton)e.getSource();
SongItem item = (SongItem)button.getParent();
int sidx = ((Integer)item.extra).intValue();
Chooser.djobj.remove(sidx, 1);
} else if (cmd.equals(PlaylistPanel.REMOVE_ALL)) {
JButton src = (JButton)e.getSource();
PlaylistPanel.PLE entry =
(PlaylistPanel.PLE)src.getClientProperty("entry");
// remove all entries starting with this one until we get to
// one that has a different entryid
int start = -1, length = 1;
for (int ii = 0; ii < _panel.plist.size(); ii++) {
PlaylistPanel.PLE pe = (PlaylistPanel.PLE)_panel.plist.get(ii);
if (entry == pe) {
start = ii;
} else if (start != -1) {
if (pe.entry.entryid == entry.entry.entryid) {
length++;
} else {
// we hit an entry that doesn't match, bail
break;
}
}
}
if (start != -1) {
Chooser.djobj.remove(start, length);
}
} else if (cmd.equals(PlaylistPanel.SHUFFLE)) {
// shuffle!
Chooser.djobj.shuffle();
} else {
return super.handleAction(e);
}
return true;
}
// documentation inherited from interface
public void attributeChanged (AttributeChangedEvent event)
{
if (event.getName().equals(DJObject.PLAYLIST)) {
TaskMaster.invokeMethodTask("readPlaylist", this, this);
} else if (event.getName().equals(DJObject.PLAYING)) {
playingUpdated();
}
}
public void readPlaylist ()
throws PersistenceException
{
// clear out any previous playlist
_panel.plist.clear();
int pcount = (Chooser.djobj.playlist == null) ? 0 :
Chooser.djobj.playlist.length;
for (int ii = 0; ii < pcount; ii++) {
PlaylistEntry pentry = Chooser.djobj.playlist[ii];
Entry entry = Chooser.model.getEntry(pentry.entryId);
if (entry != null) {
Song song = entry.getSong(pentry.songId);
if (song != null) {
_panel.plist.add(new PlaylistPanel.PLE(entry, song));
} else {
Log.warning("No song for entry? [pentry=" + pentry + "].");
}
} else {
Log.warning("Unable to load entry? [pentry=" + pentry + "].");
}
}
}
public void playingUpdated ()
{
// unhighlight whoever is playing now
if (_playing != null) {
_playing.item.setIsPlaying(false);
_playing = null;
}
int pidx = Chooser.djobj.playing;
if (pidx >= 0 && _panel.plist.size() > pidx) {
_playing = (PlaylistPanel.PLE)_panel.plist.get(pidx);
}
if (_playing != null) {
_playing.item.setIsPlaying(true);
}
_panel.repaint();
}
public void taskCompleted (String name, Object result)
{
if (name.equals("readPlaylist")) {
_panel.populatePlaylist(_panel.plist);
playingUpdated();
} else {
super.taskCompleted(name, result);
}
}
protected PlaylistPanel _panel;
protected PlaylistPanel.PLE _playing;
}
@@ -1,246 +0,0 @@
//
// $Id: PlaylistPanel.java,v 1.18 2004/02/24 12:40:24 mdb Exp $
package robodj.chooser;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Iterator;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.*;
import com.samskivert.swing.util.*;
import com.samskivert.util.StringUtil;
import robodj.Log;
import robodj.repository.*;
import robodj.util.ButtonUtil;
public class PlaylistPanel extends ControlledPanel
{
public static class PLE
{
public Entry entry;
public Song song;
public SongItem item;
public PLE (Entry entry, Song song)
{
this.entry = entry;
this.song = song;
}
public String toString ()
{
return StringUtil.fieldsToString(this);
}
}
public static final String CLEAR = "clear";
public static final String REMOVE_ALL = "remove_all";
public static final String SHUFFLE = "shuffle";
public ArrayList plist = new ArrayList();
public PlaylistPanel ()
{
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
setLayout(gl);
// create the pane that will hold the buttons
gl = new VGroupLayout(GroupLayout.NONE);
gl.setJustification(GroupLayout.TOP);
gl.setGap(2);
_bpanel = new SmartPanel();
_bpanel.setLayout(gl);
// give ourselves a wee bit of a border
_bpanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
// put it into a scrolling pane
JScrollPane bscroll = new JScrollPane(_bpanel);
add(bscroll);
GroupLayout bgl = new HGroupLayout(GroupLayout.NONE);
bgl.setJustification(GroupLayout.RIGHT);
JPanel cbar = new JPanel(bgl);
// add our control buttons
_clearbut = ButtonUtil.createControlButton(
CLEAR_TIP, CLEAR, CLEAR_ICON_PATH);
cbar.add(_clearbut);
cbar.add(ButtonUtil.createControlButton(
SHUFFLE_TIP, SHUFFLE, SHUFFLE_ICON_PATH));
add(cbar, GroupLayout.FIXED);
// use a special font for our name buttons
_nameFont = new Font("Helvetica", Font.PLAIN, 12);
// create our icons
_removeEntryIcon = ButtonUtil.getIcon(REMOVE_ENTRY_ICON_PATH);
}
// documentation inherited
public void addNotify ()
{
super.addNotify();
}
// documentation inherited
protected Controller createController ()
{
return new PlaylistController(this);
}
protected void prepareForRefresh ()
{
// stick a "loading" label in the list to let the user know
// what's up
_bpanel.removeAll();
_bpanel.add(new JLabel("Loading..."));
// swing doesn't automatically validate after adding/removing
// children
_bpanel.revalidate();
}
protected void populatePlaylist (ArrayList plist)
{
// clear out any existing children
_bpanel.removeAll();
// adjust our layout policy
GroupLayout gl = (GroupLayout)_bpanel.getLayout();
gl.setOffAxisPolicy(GroupLayout.EQUALIZE);
gl.setOffAxisJustification(GroupLayout.LEFT);
int current = Chooser.djobj.playing;
// add buttons for every entry
String title = null;
for (int ii = 0; ii < plist.size(); ii++) {
PLE entry = (PLE)plist.get(ii);
JButton button;
// add record/artist indicators when the record and artist
// changes
if (!entry.entry.title.equals(title)) {
JPanel tpanel = new JPanel();
gl = new HGroupLayout(GroupLayout.NONE);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
gl.setJustification(GroupLayout.LEFT);
tpanel.setLayout(gl);
title = entry.entry.title;
JLabel label = new JLabel(entry.entry.title + " - " +
entry.entry.artist);
tpanel.add(label);
tpanel.add(newButton(REMOVE_ENTRY_TIP, REMOVE_ALL,
_removeEntryIcon, entry));
_bpanel.add(tpanel);
}
// create a song item to display this playlist entry
entry.item = new SongItem(entry.song, SongItem.PLAYLIST);
entry.item.setIsPlaying(current == ii);
entry.item.extra = new Integer(ii);
_bpanel.add(entry.item);
// let the bpanel know that we want to scroll the active track
// label into place once we're all laid out
if (current == ii) {
_bpanel.setScrollTarget(entry.item);
}
}
// if there were no entries, stick a label in to that effect
if (plist.size() == 0) {
_bpanel.add(new JLabel("Nothing playing."));
}
// swing doesn't automatically validate after adding/removing
// children
_bpanel.revalidate();
}
protected JButton newButton (String tooltip, String command,
ImageIcon icon, Object clientProperty)
{
JButton button = ButtonUtil.createControlButton(
tooltip, command, icon, true);
button.putClientProperty("entry", clientProperty);
return button;
}
/**
* A panel that can be made to scroll a particular child into view
* when it becomes visible.
*/
protected static class SmartPanel extends ScrollablePanel
{
public void setScrollTarget (JComponent comp)
{
_target = comp;
}
public void doLayout ()
{
super.doLayout();
if (_target != null) {
Rectangle bounds = _target.getBounds();
_target = null;
// this seems to sometimes call layout(), so we need to
// prevent recursion
scrollRectToVisible(bounds);
}
}
// make the playlist fit the width of the scrolling viewport
public boolean getScrollableTracksViewportWidth ()
{
return true;
}
protected JComponent _target;
}
protected SmartPanel _bpanel;
protected JButton _clearbut;
protected Font _nameFont;
protected ImageIcon _skiptoIcon;
protected ImageIcon _removeSongIcon;
protected ImageIcon _removeEntryIcon;
// icon paths
protected static final String ICON_ROOT = "/robodj/chooser/images/";
protected static final String CLEAR_ICON_PATH = ICON_ROOT + "clear.png";
protected static final String SHUFFLE_ICON_PATH = ICON_ROOT + "shuffle.png";
protected static final String SKIPTO_ICON_PATH = ICON_ROOT + "skip.png";
protected static final String REMOVE_ENTRY_ICON_PATH =
ICON_ROOT + "remove_entry.png";
protected static final String REMOVE_SONG_ICON_PATH =
ICON_ROOT + "remove_song.png";
// button tips
protected static final String CLEAR_TIP =
"Clear all songs from the playlist";
protected static final String SHUFFLE_TIP =
"Shuffle the songs in the playlist";
protected static final String SKIPTO_TIP = "Skip to this song";
protected static final String REMOVE_ENTRY_TIP =
"Remove all songs in this entry from the playlist";
protected static final String REMOVE_SONG_TIP =
"Remove this song from the playlist";
}
@@ -1,41 +0,0 @@
//
// $Id: QueryEntryList.java,v 1.2 2003/05/04 18:16:06 mdb Exp $
package robodj.chooser;
import com.samskivert.io.PersistenceException;
import com.samskivert.swing.Controller;
import robodj.repository.Entry;
public class QueryEntryList extends EntryList
{
/**
* Constructs an entry list to display entries that match a query.
*/
public QueryEntryList (String query)
{
_query = query;
}
// documentation inherited
protected Controller createController ()
{
return new EntryController(this) {
public Entry[] readEntries () throws PersistenceException {
if (_entries == null) {
_entries = Chooser.repository.matchEntries(_query);
}
return _entries;
}
};
}
protected String getEmptyString ()
{
return "No matches to your query.";
}
/** The query with which we're looking up entries. */
protected String _query;
}
@@ -1,63 +0,0 @@
//
// $Id$
package robodj.chooser;
import com.samskivert.util.Queue;
/**
* Provides the ability to perform some basic RoboDJ commands from the
* command line.
*/
public class Remote extends DJClient
{
public void invoke (String command)
{
_command = command;
connectToServer();
}
protected void didInit ()
{
super.didInit();
if (_command.equalsIgnoreCase("play")) {
djobj.play();
} else if (_command.equalsIgnoreCase("pause")) {
djobj.pause();
} else if (_command.equalsIgnoreCase("stop")) {
djobj.stop();
} else {
System.err.println("Unknown command: " + _command);
}
exit();
}
// documentation inherited from interface
public void invokeLater (Runnable run)
{
_queue.append(run);
}
public static void main (String[] args)
{
if (args.length == 0) {
System.out.println("Usage: Remote [play|pause|stop]");
System.exit(-1);
}
Remote remote = new Remote();
remote.invoke(args[0]);
Runnable run;
while ((run = (Runnable)_queue.get()) != null) {
run.run();
}
}
protected String _command;
protected static Queue _queue = new Queue();
}
@@ -1,82 +0,0 @@
//
// $Id: SearchPanel.java,v 1.3 2002/03/03 20:56:12 mdb Exp $
package robodj.chooser;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import com.samskivert.swing.*;
import com.samskivert.util.StringUtil;
import robodj.repository.*;
public class SearchPanel extends JPanel
implements ActionListener
{
public SearchPanel ()
{
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
gl.setJustification(GroupLayout.TOP);
setLayout(gl);
// give ourselves a wee bit of a border
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(new JLabel("Enter a word to be matched against the " +
"artists, titles and songs:"), GroupLayout.FIXED);
gl = new HGroupLayout(GroupLayout.STRETCH);
JPanel qpanel = new JPanel(gl);
_qbox = new JTextField();
_qbox.addActionListener(this);
_qbox.setActionCommand("query");
qpanel.add(_qbox);
JButton qbutton = new JButton("Query");
qbutton.addActionListener(this);
qbutton.setActionCommand("query");
qpanel.add(qbutton, GroupLayout.FIXED);
add(qpanel, GroupLayout.FIXED);
}
public void actionPerformed (ActionEvent e)
{
if (e.getActionCommand().equals("query")) {
String text = _qbox.getText();
if (StringUtil.blank(text) || text.equals(_query)) {
// ignore empty text or repeat queries
return;
}
// make a note of the query
_query = text;
// remove any previous query results
if (_qlist != null) {
remove(_qlist);
_qlist = null;
}
// create and add a query entry list for the query
_qlist = new QueryEntryList(_query);
add(_qlist);
// we need to revalidate ourselves and repaint because we've
// added a component
revalidate();
repaint();
}
}
/** The most recent query. */
protected String _query;
/** The query text box. */
protected JTextField _qbox;
/** The entry list that displays the results of our query. */
protected QueryEntryList _qlist;
}
@@ -1,165 +0,0 @@
//
// $Id: SongItem.java,v 1.1 2003/05/04 18:16:06 mdb Exp $
package robodj.chooser;
import java.awt.Color;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import com.samskivert.swing.HGroupLayout;
import com.samskivert.util.StringUtil;
import robodj.repository.Song;
import robodj.util.ButtonUtil;
/**
* Displays a particular song (used by the playlist and the entry list).
*/
public class SongItem extends Item
{
/** Configures this song item for playlist mode. */
public static final int PLAYLIST = 0;
/** Configures this song item for browser mode. */
public static final int BROWSER = 1;
// playlist mode actions
public static final String SKIP_TO = "song:skip_to";
public static final String REMOVE = "song:remove";
// browser mode actions
public static final String PLAY = "song:play";
// ubiquitous actions
public static final String TOGGLE_VOTE = "song:toggle_vote";
/** Used depending on where this song is being displayed. */
public Object extra;
/**
* Creates a song item configured with the supplied song and specified
* mode.
*/
public SongItem (Song song, int mode)
{
_song = song;
// configure our layout manager
HGroupLayout gl = new HGroupLayout(HGroupLayout.NONE);
gl.setJustification(HGroupLayout.LEFT);
setLayout(gl);
// create our control buttons
JButton button;
switch (mode) {
case PLAYLIST:
// add a button for skipping to this song
button = ButtonUtil.createControlButton(
SKIP_TO_TIP, SKIP_TO, _skipToIcon, true);
button.putClientProperty("song", _song);
add(button, HGroupLayout.FIXED);
// add a button for removing this song
button = ButtonUtil.createControlButton(
REMOVE_TIP, REMOVE, _removeIcon, true);
button.putClientProperty("song", _song);
add(button, HGroupLayout.FIXED);
break;
case BROWSER:
// add a button for playing the song
button = ButtonUtil.createControlButton(
PLAY_SONG_TIP, PLAY, _playIcon, true);
button.putClientProperty(SONG_PROP, _song);
add(button, HGroupLayout.FIXED);
break;
default:
System.err.println("Unknown song mode: " + mode);
break;
}
// add a vote button
_voteButton = ButtonUtil.createControlButton(
TOGGLE_VOTE_TIP, TOGGLE_VOTE, _noVoteIcon, true);
_voteButton.putClientProperty(SONG_PROP, song);
add(_voteButton, HGroupLayout.FIXED);
// add the song title
_trackLabel = new JLabel(_song.title);
add(_trackLabel);
// update our display based on our votes
update();
}
public void setIsPlaying (boolean isPlaying)
{
_trackLabel.setForeground(isPlaying ? Color.red : Color.black);
}
public void update ()
{
if (!StringUtil.blank(_song.votes)) {
_trackLabel.setFont(_hasVotesFont);
_trackLabel.setToolTipText(
"<html><table><tr><td>" + _song.title + "</td></tr>" +
"<tr><td>Votes: " + _song.votes + "</td></tr>" +
"</table></html>");
} else {
_trackLabel.setFont(_nameFont);
_trackLabel.setToolTipText(_song.title);
}
switch (_song.hasVoted(Chooser.frame.getUser(false))) {
case -1: _voteButton.setIcon(_nayVoteIcon); break;
case 1: _voteButton.setIcon(_yeaVoteIcon); break;
default:
case 0: _voteButton.setIcon(_noVoteIcon); break;
}
repaint();
}
public Song getSong ()
{
return _song;
}
public static Song getSong (Object source)
{
return (Song)((JButton)source).getClientProperty(SONG_PROP);
}
protected Song _song;
protected JButton _voteButton;
protected JLabel _trackLabel;
protected static final String SONG_PROP = "song";
protected static final String SKIP_TO_TIP =
"Skip to this song";
protected static final String REMOVE_TIP =
"Remove this song from the playlist";
protected static final String PLAY_SONG_TIP =
"Append this song to the playlist";
protected static final String TOGGLE_VOTE_TIP =
"Toggle your vote for this song";
protected static ImageIcon _skipToIcon =
ButtonUtil.getIcon(ICON_ROOT + "skip.png");
protected static ImageIcon _removeIcon =
ButtonUtil.getIcon(ICON_ROOT + "remove_song.png");
protected static ImageIcon _yeaVoteIcon =
ButtonUtil.getIcon(ICON_ROOT + "yea_vote.png");
protected static ImageIcon _nayVoteIcon =
ButtonUtil.getIcon(ICON_ROOT + "nay_vote.png");
protected static ImageIcon _noVoteIcon =
ButtonUtil.getIcon(ICON_ROOT + "no_vote.png");
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 681 B

@@ -1,16 +0,0 @@
//
// $Id$
package robodj.client;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
/**
* Defines the main RoboDJ services.
*/
public interface DJService extends InvocationService
{
/** Used to obtain the oid of the DJ object. */
public void getDJOid (Client client, ResultListener listener);
}
@@ -1,33 +0,0 @@
#
# $Id: config.properties,v 1.1 2003/05/04 18:16:06 mdb Exp $
#
# Default RoboDJ configuration properties
#
# The directory in which RoboDJ will store its ripped music
# repository.basedir = /export/robodj/repository
#
# The directory in which the importer will store temp files while ripping
# repository.tmpdir = /export/robodj/tmp
#
# The JDBC configuration for accessing the music database
jdbc.default.driver = org.gjt.mm.mysql.Driver
jdbc.default.username = _USERNAME_
jdbc.default.password = _PASSWORD_
jdbc.default.url = jdbc:mysql://_DBHOST_:3306/_DBNAME_
#
# The CDDB host to which to connect
cddb.host = freedb.freedb.org
#
# The music server host and port information
# musicd.host = hostname
musicd.port = 2500
@@ -1,204 +0,0 @@
//
// $Id: CDParanoiaRipper.java,v 1.9 2003/10/24 18:34:28 mdb Exp $
package robodj.convert;
import java.io.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.PatternSyntaxException;
/**
* A ripper implementation that uses cdparanoia to do it's job.
*/
public class CDParanoiaRipper implements Ripper
{
public TrackInfo[] getTrackInfo ()
throws ConvertException
{
// an input line that we're interested in looks something like
// this:
//
// 1. 17980 [03:59.55] 0 [00:00.00] no no 2
Pattern regex;
try {
regex = Pattern.compile(
"^\\s*\\d+\\.\\s+(\\d+)\\s\\[\\S*\\]\\s+(\\d+)");
} catch (PatternSyntaxException pse) {
throw new ConvertException("Can't compile regexp?! " + pse);
}
try {
// fork off a cdparanoia process to read the TOC
Runtime rt = Runtime.getRuntime();
Process tocproc = rt.exec("cdparanoia -Q");
InputStream in = tocproc.getErrorStream();
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
String inline;
StringBuffer input = new StringBuffer();
ArrayList flist = new ArrayList();
while ((inline = din.readLine()) != null) {
// skip blank lines and lines that are in the header
if (inline.trim().length() == 0 ||
inline.indexOf("xiph.org") != -1 ||
inline.indexOf("mit.edu") != -1 ||
inline.indexOf("cdparanoia") == 0) {
continue;
}
// keep track of all of the input in case we need to
// report an error later
input.append(inline).append("\n");
// see if we match our regular expression
Matcher match = regex.matcher(inline);
if (match.find()) {
flist.add(inline.substring(match.start(1), match.end(1)));
flist.add(inline.substring(match.start(2), match.end(2)));
}
}
// check the return value of the process
try {
int retval = tocproc.waitFor();
if (retval != 0) {
// ship off the error output from cdparanoia
throw new ConvertException(input.toString());
}
} 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 " +
"cdparanoia process to exit.");
}
// parse the frame offsets and stick them in an array
TrackInfo[] frames = new TrackInfo[flist.size()/2];
for (int i = 0; i < frames.length; i++) {
try {
frames[i] = new TrackInfo();
frames[i].length =
Integer.parseInt((String)flist.get(2*i));
frames[i].offset =
Integer.parseInt((String)flist.get(2*i+1));
// for some reason, cdparanoia reports track offsets
// starting from zero but CDDB assumes they start at 2
// seconds, so we have to adjust... sigh.
frames[i].offset += 2 * RipUtil.FRAMES_PER_SECOND;
} catch (NumberFormatException nfe) {
throw new ConvertException(
"Bogus frame value for track " + (i+1) + ": " +
nfe.getMessage() + "\n\n" + input);
}
}
return frames;
} catch (IOException ioe) {
throw new ConvertException(
"Error communicating with ripper:\n" + ioe);
}
}
public void ripTrack (TrackInfo[] info, int index, String target,
ConversionProgressListener listener)
throws ConvertException
{
StringBuffer cmd = new StringBuffer("nice cdparanoia");
cmd.append(" -w"); // request output in WAV format
cmd.append(" -e"); // request progress information to stderr
cmd.append(" ").append(index); // add track number
cmd.append(" ").append(target); // add output file name
// we'll need this for later
Pattern regex;
try {
regex = Pattern.compile("^##: -?\\d+ \\[(\\S+)\\] @ (\\d+)");
} catch (PatternSyntaxException pse) {
throw new ConvertException("Can't compile regexp?! " + pse);
}
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;
// figure out what our progress boundaries are
long tstart = info[index-1].offset * MAGIC_FACTOR;
long tlength = info[index-1].length * MAGIC_FACTOR;
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
Matcher match = regex.matcher(out);
if (match.matches()) {
String action = out.substring(match.start(1), match.end(1));
long offset = -1L;
try {
offset = Long.parseLong(
out.substring(match.start(2), match.end(2)));
} catch (NumberFormatException nfe) {
// System.err.println("Malformed pos. info: " + out);
continue;
}
int pctDone = (int)(100 * (offset - tstart) / tlength);
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(
"Ripper 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 " +
"ripper process to exit.");
}
// if everything was successful, report completion
listener.updateProgress(100);
} catch (IOException ioe) {
throw new ConvertException(
"Error communicating with ripper:\n" + ioe);
}
}
// cdparanoia reports length in sectors and progress in
protected static final int MAGIC_FACTOR = 1176;
}
@@ -1,22 +0,0 @@
//
// $Id: ConversionProgressListener.java,v 1.2 2001/02/06 08:18:00 mdb Exp $
package robodj.convert;
/**
* This interface is used to communicate ripping progress from a ripper or
* encoder implementation to code using the conversion services (and
* hopefully ultimately to the end user).
*/
public interface ConversionProgressListener
{
/**
* Informs the listener that the converter has completed the specified
* percentage of the conversion process. The percentage should reflect
* only the conversion being performed by the converter at that time
* (ripping or converting a single track). The information provided
* herein will be mapped to a global progress indication by the
* calling software (in the case of converting an entire CD).
*/
public void updateProgress (int percentComplete);
}
@@ -1,17 +0,0 @@
//
// $Id: ConvertException.java,v 1.1 2000/10/30 22:21:11 mdb Exp $
package robodj.convert;
/**
* A convert exception can be thrown to indicate that some problem was
* encountered during some part of the conversion process (ripping or
* encoding).
*/
public class ConvertException extends Exception
{
public ConvertException (String message)
{
super(message);
}
}
@@ -1,33 +0,0 @@
//
// $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);
}
}
}
@@ -1,28 +0,0 @@
//
// $Id: Encoder.java,v 1.1 2000/10/30 22:21:11 mdb Exp $
package robodj.convert;
/**
* The encoder interface is used to manipulate particular MP3 encoding
* software in the ways needed by the RoboDJ system.
*/
public interface Encoder
{
/**
* Instructs the encoder to encode the specified track.
*
* @param source the path to the source file that should be encoded.
* @param dest the path to the destination file which should be
* created by the encoder.
* @param listener a callback object that should be called to
* communicate encoding progress. If the listener parameter is null,
* the caller doesn't want to hear about progress (shame on them).
*
* @exception ConvertException can be thrown if anything fails during
* the encoding process.
*/
public void encodeTrack (String source, String dest,
ConversionProgressListener listener)
throws ConvertException;
}
@@ -1,77 +0,0 @@
//
// $Id: ID3Tagger.java,v 1.3 2002/11/11 17:04:56 mdb Exp $
package robodj.convert;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
/**
* A tagger implementation that uses 'id3v2' to do it's job.
*/
public class ID3Tagger implements Tagger
{
// documentation inherited
public void idTrack (String target, String artist, String album,
String title, int trackNo)
throws ConvertException
{
String[] cmdarray = new String[] {
"id3v2", "--song", title, "--artist", artist, "--album", album,
"--track", Integer.toString(trackNo), target };
try {
Runtime rt = Runtime.getRuntime();
Process ripproc = rt.exec(cmdarray);
InputStream in = ripproc.getErrorStream();
String output = IOUtils.toString(in);
// check the return value of the process
try {
int retval = ripproc.waitFor();
if (retval != 0) {
// ship off the error output from id3
throw new ConvertException(
"id3v2 failed: " + output);
}
} 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.");
}
} catch (IOException ioe) {
throw new ConvertException(
"Error communicating with encoder:\n" + ioe);
}
}
public static void main (String[] args)
{
ID3Tagger tagger = new ID3Tagger();
if (args.length < 5) {
System.err.println("Usage: ID3Tagger target artist album " +
"title trackNo");
System.exit(-1);
}
int trackNo = 0;
try {
trackNo = Integer.parseInt(args[4]);
} catch (NumberFormatException nfe) {
System.err.println("Invalid track number: " + args[4]);
System.exit(-1);
}
try {
tagger.idTrack(args[0], args[1], args[2], args[3], trackNo);
} catch (ConvertException ce) {
ce.printStackTrace(System.err);
}
}
}
@@ -1,58 +0,0 @@
//
// $Id: L3Encoder.java,v 1.2 2003/10/10 19:33:16 mdb Exp $
package robodj.convert;
import java.io.*;
/**
* An encoder implementation that uses the Fraunhofer-IIS L3ENC mp3
* encoding program.
*/
public class L3Encoder implements Encoder
{
public void encodeTrack (String source, String dest,
ConversionProgressListener listener)
throws ConvertException
{
StringBuffer cmd = new StringBuffer("nice l3enc");
cmd.append(" ").append(source); // add input file name
cmd.append(" ").append(dest); // add output file name
cmd.append(" -br 128000"); // request 128kbps encoding
try {
// fork off a cdparanoia process to read the TOC
Runtime rt = Runtime.getRuntime();
Process encproc = rt.exec(cmd.toString());
InputStream in = encproc.getErrorStream();
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
// read output from the subprocess and chuck it for now
while (din.readLine() != null) {
// la la la
}
// check the return value of the process
try {
int retval = encproc.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.");
}
} catch (IOException ioe) {
throw new ConvertException(
"Error communicating with encoder:\n" + ioe);
}
}
}
@@ -1,108 +0,0 @@
//
// $Id: LameEncoder.java,v 1.4 2003/10/24 18:34:28 mdb Exp $
package robodj.convert;
import java.io.*;
import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.PatternSyntaxException;
/**
* 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("nice 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
Pattern regex;
try {
// a line of input looks like this
// 0/1273 ( 0%)| 0:00/ 0:00...
regex = Pattern.compile("^\\s*(\\d+)/(\\d+)\\s*\\(.*");
} catch (PatternSyntaxException pse) {
throw new ConvertException("Can't compile regexp?! " + pse);
}
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
Matcher match = regex.matcher(out);
if (match.matches()) {
int offset = -1, total = -1;
try {
offset = Integer.parseInt(
out.substring(match.start(1), match.end(1)));
total = Integer.parseInt(
out.substring(match.start(2), match.end(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);
}
}
}
@@ -1,109 +0,0 @@
//
// $Id: RipTest.java,v 1.4 2001/03/18 06:58:55 mdb Exp $
package robodj.convert;
import com.samskivert.net.cddb.*;
public class RipTest
{
public static void lookupCDDB (String hostname, Ripper.TrackInfo[] info)
throws Exception
{
CDDB cddb = new CDDB();
long discid = RipUtil.computeDiscId(info);
String cdid = Long.toString(discid, 0x10);
// create an array with the track offsets
int[] offsets = new int[info.length];
for (int i = 0; i < info.length; i++) {
offsets[i] = info[i].offset;
}
int length = RipUtil.computeDiscLength(info);
try {
System.out.println("connecting to: " + hostname);
String rsp = cddb.connect(hostname);
// set the timeout to 30 seconds
cddb.setTimeout(30*1000);
// try a test query
CDDB.Entry[] entries = cddb.query(cdid, offsets, length);
if (entries == null || entries.length == 0) {
System.out.println("No match for " + cdid + ".");
} else {
for (int i = 0; i < entries.length; i++) {
System.out.println("Match " + entries[i].category + "/" +
entries[i].cdid + "/" +
entries[i].title);
}
CDDB.Detail detail = cddb.read(entries[0].category,
entries[0].cdid);
System.out.println("Title: " + detail.title);
for (int i = 0; i < detail.trackNames.length; i++) {
System.out.println(pad(i) + ": " + detail.trackNames[i]);
}
System.out.println("Extended data: " + detail.extendedData);
for (int i = 0; i < detail.extendedTrackData.length; i++) {
System.out.println(pad(i) + ": " +
detail.extendedTrackData[i]);
}
}
} finally {
cddb.close();
}
}
protected static String pad (int value)
{
return ((value > 9) ? "" : " ") + value;
}
public static void main (String[] args)
{
try {
Ripper ripper = new CDParanoiaRipper();
Ripper.TrackInfo[] info = ripper.getTrackInfo();
for (int i = 0; i < info.length; i++) {
System.out.println((i+1) + ": " + info[i].offset + ", " +
info[i].length);
}
if (info.length == 0) {
System.out.println("Matched no tracks?!");
} else {
// try the CDDB lookup
lookupCDDB("ca.freedb.org", info);
// rip a track, for fun
int track = 2;
System.out.println("Ripping track " + track +
" [" + info[track-1].offset +
", " + info[track-1].length + "]...");
// report our progress
ConversionProgressListener listener =
new ConversionProgressListener() {
public void updateProgress (int percentDone)
{
System.out.println("Percent done: " +
percentDone + "%");
}
};
ripper.ripTrack(info, track, "/tmp/track" + track + ".wav",
listener);
}
} catch (Exception e) {
System.err.println("Error: " + e);
}
}
}
@@ -1,72 +0,0 @@
//
// $Id: RipUtil.java,v 1.3 2003/10/24 18:34:28 mdb Exp $
package robodj.convert;
import com.samskivert.util.StringUtil;
/**
* This class contains utility functions related to ripping.
*/
public class RipUtil
{
/**
* Compact discs contain this many frames per second.
*/
public static int FRAMES_PER_SECOND = 75;
/**
* Computes the CDDB disc id for the specified CD using the supplied
* track info.
*/
public static long computeDiscId (Ripper.TrackInfo[] info)
{
// first we sum all the digits in the numbers that represent the
// number of seconds for each track
long digits = 0;
for (int i = 0; i < info.length; i++) {
int secs = info[i].offset/FRAMES_PER_SECOND;
digits += addDigits(secs);
}
// determine the total number of seconds of all the tracks on the
// CD (doing so by subtracting the offset of the end of the disc
// from the offset of the beginning which is how the CDDB
// algorithm does it)
long totsecs = (long)computeDiscLength(info);
// finally combine these two values with the number of tracks on
// the disc into the actual disc id
return ((digits & 0xFF) << 24) | (totsecs << 8) | info.length;
}
/**
* @return the length of the CD (in seconds) as computed from the
* supplied frame information.
*/
public static int computeDiscLength (Ripper.TrackInfo[] info)
{
if (info == null || info.length == 0) {
String errmsg = "Must have at least one track to compute disc " +
"length [info=" + StringUtil.toString(info) + "]";
throw new IllegalArgumentException(errmsg);
}
return (info[info.length-1].offset +
info[info.length-1].length -
info[0].offset)/FRAMES_PER_SECOND;
}
/**
* @return the sum of the digits in the supplied number (eg. 6 for 15,
* 8 for 251, etc.).
*/
protected static int addDigits (int value)
{
int rv = 0;
while (value > 0) {
rv += value%10;
value /= 10;
}
return rv;
}
}
@@ -1,66 +0,0 @@
//
// $Id: Ripper.java,v 1.3 2001/02/06 08:18:00 mdb Exp $
package robodj.convert;
/**
* The ripper interface is used to manipulate particular CD ripping
* software in the ways needed by the RoboDJ system.
*/
public interface Ripper
{
/**
* Instances of this object are used to communicate the track
* information of a CD back to the caller.
*/
public class TrackInfo
{
/**
* The offset of the start of this track (in frames).
*/
public int offset;
/**
* The length of this track (in frames).
*/
public int length;
}
/**
* This function should return an array with an entry for each track
* on the CD (in order) containing the frame offset and length of that
* track. This function will be called in another thread and has 30
* seconds to do its job or it will be declared delinquent and
* ignored.
*
* @exception ConvertException can be thrown if some problem occurs
* trying to read the CD table of contents (like lack of access to the
* CDROM device or any other errors).
*/
public TrackInfo[] getTrackInfo ()
throws ConvertException;
/**
* Instructs the ripper to rip the track with the supplied index into
* the file specified by target. If the ripper supports progress
* notification, it should communicate it to the supplied progress
* listener. The track should be ripped in WAV format.
*
* @param info the track info as returned by
* <code>getTrackInfo</code>. This is necessary to compute progress.
* @param index the track number of the track to rip (starting at 1
* since CDs start counting tracks at 1).
* @param target the path to the file into which the track should be
* ripped.
* @param listener a callback object that should be called to
* communicate ripping progress. If the listener parameter is null,
* the caller doesn't want to hear about progress (shame on them).
*
* @exception ConvertException can be thrown if some problem occurs
* trying to rip the specified track (like lack of access to the CDROM
* device or any other errors).
*/
public void ripTrack (TrackInfo[] info, int index, String target,
ConversionProgressListener listener)
throws ConvertException;
}
@@ -1,19 +0,0 @@
//
// $Id: Tagger.java,v 1.1 2002/03/03 05:25:10 mdb Exp $
package robodj.convert;
/**
* The tagger interface is used to set the ID3 tags in MP3 files.
*/
public interface Tagger
{
/**
* Sets the ID3 tags for the specified target MP3 file for the
* supplied information: artist, album name, track title and track
* number.
*/
public void idTrack (String target, String artist, String album,
String title, int trackNo)
throws ConvertException;
}
@@ -1,35 +0,0 @@
//
// $Id$
package robodj.data;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService.ResultListener;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
import robodj.client.DJService;
/**
* Provides the implementation of the {@link DJService} interface
* that marshalls the arguments and delivers the request to the provider
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*/
public class DJMarshaller extends InvocationMarshaller
implements DJService
{
/** The method id used to dispatch {@link #getDJOid} requests. */
public static final int GET_DJOID = 1;
// documentation inherited from interface
public void getDJOid (Client arg1, ResultListener arg2)
{
ResultMarshaller listener2 = new ResultMarshaller();
listener2.listener = arg2;
sendRequest(arg1, GET_DJOID, new Object[] {
listener2
});
}
}
@@ -1,133 +0,0 @@
//
// $Id$
package robodj.data;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.ListUtil;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DSet;
import robodj.Log;
/**
* Contains the shared state of RoboDJ.
*/
public class DJObject extends DObject
{
/** The current playlist. */
public PlaylistEntry[] playlist;
/** The index of the currently playing track. */
public int playing = -1;
/** Whether or not we're paused. */
public boolean paused;
/**
* Returns the currently playing track.
*/
public PlaylistEntry getPlaying ()
{
return (playing < 0) ? null : getEntry(playing);
}
/**
* Returns the playlist entry for the next song in the playlist.
*/
public PlaylistEntry getNext ()
{
return (playing < 0) ? null : getEntry(playing + 1);
}
/**
* Returns the playlist entry with the current index or null if the
* index is not valid.
*/
public PlaylistEntry getEntry (int index)
{
return havePlaylist() ? playlist[index % playlist.length] : null;
}
/**
* Plays the specified track in the current playlist.
*/
public void play (int index)
{
if (havePlaylist()) {
setPlaying(index % playlist.length);
}
}
public void play ()
{
if (havePlaylist()) {
if (playing == -1) {
setPlaying(0);
}
if (paused) {
setPaused(false);
}
}
}
public void skip ()
{
if (havePlaylist()) {
play(playing + 1);
}
}
public void back ()
{
if (havePlaylist()) {
play(playing + playlist.length - 1);
}
}
public void stop ()
{
setPlaying(-1);
}
public void pause ()
{
setPaused(!paused);
}
public void remove (int start, int length)
{
if (havePlaylist()) {
setPlaylist((PlaylistEntry[])ArrayUtil.splice(
playlist, start, length));
if (playing >= (start+length)) {
setPlaying(playing-length);
} else if (playing > start) {
setPlaying(start);
}
}
}
public void shuffle ()
{
if (havePlaylist()) {
PlaylistEntry entry = getPlaying();
ArrayUtil.shuffle(playlist);
setPlaylist(playlist);
setPlaying(ListUtil.indexOf(playlist, entry));
}
}
public void clear ()
{
setPlaying(-1);
setPlaylist(null);
}
/** Helper function. */
protected boolean havePlaylist ()
{
return (playlist != null && playlist.length > 0);
}
}
@@ -1,198 +0,0 @@
//
// $Id$
package robodj.data;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.ListUtil;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DSet;
import robodj.Log;
/**
* Contains the shared state of RoboDJ.
*/
public class DJObject extends DObject
{
/** The field name of the <code>playlist</code> field. */
public static final String PLAYLIST = "playlist";
/** The field name of the <code>playing</code> field. */
public static final String PLAYING = "playing";
/** The field name of the <code>paused</code> field. */
public static final String PAUSED = "paused";
/** The current playlist. */
public PlaylistEntry[] playlist;
/** The index of the currently playing track. */
public int playing = -1;
/** Whether or not we're paused. */
public boolean paused;
/**
* Returns the currently playing track.
*/
public PlaylistEntry getPlaying ()
{
return (playing < 0) ? null : getEntry(playing);
}
/**
* Returns the playlist entry for the next song in the playlist.
*/
public PlaylistEntry getNext ()
{
return (playing < 0) ? null : getEntry(playing + 1);
}
/**
* Returns the playlist entry with the current index or null if the
* index is not valid.
*/
public PlaylistEntry getEntry (int index)
{
return havePlaylist() ? playlist[index % playlist.length] : null;
}
/**
* Plays the specified track in the current playlist.
*/
public void play (int index)
{
if (havePlaylist()) {
setPlaying(index % playlist.length);
}
}
public void play ()
{
if (havePlaylist()) {
if (playing == -1) {
setPlaying(0);
}
if (paused) {
setPaused(false);
}
}
}
public void skip ()
{
if (havePlaylist()) {
play(playing + 1);
}
}
public void back ()
{
if (havePlaylist()) {
play(playing + playlist.length - 1);
}
}
public void stop ()
{
setPlaying(-1);
}
public void pause ()
{
setPaused(!paused);
}
public void remove (int start, int length)
{
if (havePlaylist()) {
setPlaylist((PlaylistEntry[])ArrayUtil.splice(
playlist, start, length));
if (playing >= (start+length)) {
setPlaying(playing-length);
} else if (playing > start) {
setPlaying(start);
}
}
}
public void shuffle ()
{
if (havePlaylist()) {
PlaylistEntry entry = getPlaying();
ArrayUtil.shuffle(playlist);
setPlaylist(playlist);
setPlaying(ListUtil.indexOf(playlist, entry));
}
}
public void clear ()
{
setPlaying(-1);
setPlaylist(null);
}
/** Helper function. */
protected boolean havePlaylist ()
{
return (playlist != null && playlist.length > 0);
}
/**
* Requests that the <code>playlist</code> field be set to the specified
* value. The local value will be updated immediately and an event
* will be propagated through the system to notify all listeners that
* the attribute did change. Proxied copies of this object (on
* clients) will apply the value change when they received the
* attribute changed notification.
*/
public void setPlaylist (PlaylistEntry[] playlist)
{
requestAttributeChange(PLAYLIST, playlist);
this.playlist = playlist;
}
/**
* Requests that the <code>index</code>th element of
* <code>playlist</code> field be set to the specified value. The local
* value will be updated immediately and an event will be propagated
* through the system to notify all listeners that the attribute did
* change. Proxied copies of this object (on clients) will apply the
* value change when they received the attribute changed notification.
*/
public void setPlaylistAt (PlaylistEntry value, int index)
{
requestElementUpdate(PLAYLIST, value, index);
this.playlist[index] = value;
}
/**
* Requests that the <code>playing</code> field be set to the specified
* value. The local value will be updated immediately and an event
* will be propagated through the system to notify all listeners that
* the attribute did change. Proxied copies of this object (on
* clients) will apply the value change when they received the
* attribute changed notification.
*/
public void setPlaying (int playing)
{
requestAttributeChange(PLAYING, new Integer(playing));
this.playing = playing;
}
/**
* Requests that the <code>paused</code> field be set to the specified
* value. The local value will be updated immediately and an event
* will be propagated through the system to notify all listeners that
* the attribute did change. Proxied copies of this object (on
* clients) will apply the value change when they received the
* attribute changed notification.
*/
public void setPaused (boolean paused)
{
requestAttributeChange(PAUSED, new Boolean(paused));
this.paused = paused;
}
}
@@ -1,71 +0,0 @@
//
// $Id$
package robodj.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.presents.dobj.DSet;
import robodj.repository.Entry;
import robodj.repository.Song;
/**
* Defines an entry currently in the playlist.
*/
public class PlaylistEntry extends SimpleStreamableObject
implements DSet.Entry
{
/** The album with which we are associated. */
public int entryId;
/** The id of the song represented by this entry. */
public int songId;
/** The title of this entry (duplicated from the Song to simplify
* playlist display. */
public String title;
/** Zero argument constructor for streaming. */
public PlaylistEntry ()
{
}
/** Creates a playlist entry from the specified entry and song. */
public PlaylistEntry (Entry entry, Song song)
{
this(entry.entryid, song.songid, song.title);
}
/** Creates a playlist entry from the specified information. */
public PlaylistEntry (int entryId, int songId, String title)
{
this.entryId = entryId;
this.songId = songId;
this.title = title;
_key = entryId + ":" + songId;
}
// documentation inherited
public Comparable getKey ()
{
return _key;
}
// documentation inherited
public boolean equals (Object other)
{
if (other instanceof PlaylistEntry) {
return _key.equals(((PlaylistEntry)other)._key);
} else {
return false;
}
}
// documentation inherited
public int hashCode ()
{
return _key.hashCode();
}
protected String _key;
}
@@ -1,200 +0,0 @@
//
// $Id: CDDBLookupPanel.java,v 1.7 2003/05/04 18:16:07 mdb Exp $
package robodj.importer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.*;
import com.samskivert.net.cddb.CDDB;
import com.samskivert.swing.util.*;
import com.samskivert.swing.*;
import com.samskivert.util.StringUtil;
import robodj.convert.*;
import robodj.repository.*;
public class CDDBLookupPanel
extends ImporterPanel
implements ActionListener, TaskObserver
{
public CDDBLookupPanel ()
{
GroupLayout gl = new HGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
setLayout(gl);
// create our label for the left hand side
JLabel cdlabel = new JLabel("CDDB Lookup", JLabel.CENTER);
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);
// 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, boolean popped)
{
// keep this for later
_frame = frame;
frame.addControlButton("Cancel", "cancel", this);
frame.addControlButton("Back", "back", this);
_next = frame.addControlButton("Next...", "next", this);
_next.setEnabled(popped);
// if we are being shown for the first time...
if (!popped) {
// create our info task and set it a running
TaskMaster.invokeTask("getinfo", new TaskAdapter() {
public Object invoke () throws Exception {
Ripper ripper = new CDParanoiaRipper();
return ripper.getTrackInfo();
}
}, this);
}
}
public void taskCompleted (String name, Object result)
{
if (name.equals("getinfo")) {
_info = (Ripper.TrackInfo[])result;
final Ripper.TrackInfo[] info = _info;
_infoText.append("\nRead info for " + _info.length +
" tracks.\nDoing CDDB lookup...");
// create our cddb lookup task and start it up
Task infoTask = new Task()
{
public Object invoke ()
throws Exception
{
return CDDBUtil.doCDDBLookup("freedb.freedb.org", info);
}
public boolean abort ()
{
return false;
}
};
TaskMaster.invokeTask("cddb_lookup", infoTask, this);
} else if (name.equals("cddb_lookup")) {
// get our hands on the CDDB details
CDDB.Detail[] details = (CDDB.Detail[])result;
// replace the info text with the CD info editor
remove(_spanel);
_infoEditor = new CDInfoEditor(details, _info.length);
add(_infoEditor);
// enable the next button
_next.setEnabled(true);
// relay everything out
validate();
}
}
public void taskFailed (String name, Throwable exception)
{
if (name.equals("getinfo")) {
_infoText.append("\n\nUnable to read CD info:\n\n" +
exception.getMessage());
} else if (name.equals("cddb_lookup")) {
_infoText.append("\n\nCDDB lookup failed: " +
exception.getMessage());
exception.printStackTrace();
}
}
public void actionPerformed (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals("cancel")) {
System.exit(0);
} else if (cmd.equals("back")) {
// pop back to the last panel
_frame.popPanel();
} else if (cmd.equals("next")) {
extractEntryAndContinue();
} else {
System.out.println("Unknown action event: " + cmd);
}
}
protected void extractEntryAndContinue ()
{
Entry entry = new Entry();
entry.title = _infoEditor.getTitle();
if (!validate(entry.title, "Title cannot be blank.")) {
return;
}
entry.artist = _infoEditor.getArtist();
if (!validate(entry.artist, "Artist cannot be blank.")) {
return;
}
String[] names = _infoEditor.getTrackNames();
entry.songs = new Song[names.length];
for (int i = 0; i < names.length; i++) {
if (!validate(names[i], "Track " + (i+1) +
" cannot be blank.")) {
return;
}
Song song = (entry.songs[i] = new Song());
song.title = names[i];
song.position = i+1;
song.votes = "";
}
// create the rip panel and pass the entry and info along
_frame.pushPanel(new RipPanel(_info, entry));
}
protected boolean validate (String value, String errmsg)
{
if (StringUtil.blank(value)) {
JOptionPane.showMessageDialog(SwingUtilities.getRootPane(this),
errmsg, "Invalid data provided",
JOptionPane.WARNING_MESSAGE);
return false;
}
return true;
}
protected ImporterFrame _frame;
protected JButton _next;
protected JPanel _spanel;
protected JTextArea _infoText;
protected CDInfoEditor _infoEditor;
protected Ripper.TrackInfo[] _info;
}
@@ -1,64 +0,0 @@
//
// $Id: CDDBUtil.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
package robodj.importer;
import com.samskivert.net.cddb.*;
import robodj.convert.Ripper;
import robodj.convert.RipUtil;
public class CDDBUtil
{
/**
* Does a CDDB lookup for the supplied CD information and returns an
* array of disc info objects containing the name information returned
* from CDDB.
*
* @return An array of detail objects, one per match or a zero length
* array if no matches were found.
*/
public static CDDB.Detail[] doCDDBLookup (String hostname,
Ripper.TrackInfo[] info)
throws Exception
{
CDDB cddb = new CDDB();
long discid = RipUtil.computeDiscId(info);
String cdid = Long.toString(discid, 0x10);
// create an array with the track offsets
int[] offsets = new int[info.length];
for (int i = 0; i < info.length; i++) {
offsets[i] = info[i].offset;
}
int length = RipUtil.computeDiscLength(info);
try {
String rsp = cddb.connect(hostname);
// set the timeout to 30 seconds
cddb.setTimeout(30*1000);
// try a test query
CDDB.Entry[] entries = cddb.query(cdid, offsets, length);
CDDB.Detail[] details;
if (entries == null || entries.length == 0) {
details = new CDDB.Detail[0];
} else {
details = new CDDB.Detail[entries.length];
for (int i = 0; i < entries.length; i++) {
details[i] = cddb.read(entries[i].category,
entries[i].cdid);
}
}
return details;
} finally {
cddb.close();
}
}
}
@@ -1,226 +0,0 @@
//
// $Id: CDInfoEditor.java,v 1.3 2001/06/05 17:41:00 mdb Exp $
package robodj.importer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.StringTokenizer;
import com.samskivert.swing.*;
import com.samskivert.net.cddb.CDDB;
public class CDInfoEditor
extends JPanel
{
public CDInfoEditor (CDDB.Detail[] details, int numTracks)
{
GroupLayout gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
setLayout(gl);
// create the selection components
JPanel selPanel = new JPanel(new HGroupLayout(GroupLayout.STRETCH));
JLabel selLabel = new JLabel("Select...");
// create a string array for our combo box
String[] names = new String[details.length + 1];
for (int i = 0; i < details.length; i++) {
names[i] = details[i].title;
}
names[details.length] = "<blank>";
_selBox = new JComboBox(names);
selPanel.add(selLabel, GroupLayout.FIXED);
selPanel.add(_selBox);
_selBox.addActionListener(new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
JComboBox cb = (JComboBox)e.getSource();
selectDetail(cb.getSelectedIndex());
}
});
add(selPanel, GroupLayout.FIXED);
// create the table model because we need it to listen to the
// title and artist text fields
_tmodel = new DetailTableModel(details, numTracks);
// create the title editing components
JPanel titPanel = new JPanel(new HGroupLayout(GroupLayout.STRETCH));
JLabel titLabel = new JLabel("Title");
_titText = new JTextField();
_titText.getDocument().addDocumentListener(_tmodel);
_titText.getDocument().putProperty("name", "title");
titPanel.add(titLabel, GroupLayout.FIXED);
titPanel.add(_titText);
add(titPanel, GroupLayout.FIXED);
// create the artist editing components
JPanel artPanel = new JPanel(new HGroupLayout(GroupLayout.STRETCH));
JLabel artLabel = new JLabel("Artist");
_artText = new JTextField();
_artText.getDocument().addDocumentListener(_tmodel);
_artText.getDocument().putProperty("name", "artist");
artPanel.add(artLabel, GroupLayout.FIXED);
artPanel.add(_artText);
add(artPanel, GroupLayout.FIXED);
// create the track table
_trackTable = new JTable(_tmodel);
TableColumn tcol = _trackTable.getColumnModel().getColumn(0);
// i wish this fucking worked
// tcol.sizeWidthToFit();
// then i wouldn't have do this nasty hack
tcol.setMaxWidth(20);
// make something for it to scroll around in
JScrollPane tscroll = new JScrollPane(_trackTable);
add(tscroll);
JPanel butPanel = new JPanel(new HGroupLayout(GroupLayout.NONE));
JButton fixCaseBtn = new JButton("Canonicalize text");
fixCaseBtn.addActionListener(new ActionListener () {
public void actionPerformed (ActionEvent ae) {
fixCase();
}
});
butPanel.add(fixCaseBtn);
add(butPanel, GroupLayout.FIXED);
selectDetail(0);
}
public String getTitle ()
{
return _tmodel.getTitle();
}
public String getArtist ()
{
return _tmodel.getArtist();
}
public String[] getTrackNames ()
{
// commit any uncommitted edits the user might have in progress
TableCellEditor editor = _trackTable.getCellEditor();
if (editor != null) {
editor.stopCellEditing();
}
return _tmodel.getTrackNames();
}
/**
* Cleans up the case of the track, title and artist text. This
* currently means capitalizing every word and performing some case
* fixups according to an exception list.
*/
public void fixCase ()
{
// clean up the title
String title = fixCase(_tmodel.getTitle());
_tmodel.setTitle(title);
_titText.setText(title);
// clean up the artist
String artist = fixCase(_tmodel.getArtist());
_tmodel.setArtist(artist);
_artText.setText(artist);
// clean up the tracks
String[] names = getTrackNames();
for (int i = 0; i < names.length; i++) {
_tmodel.setTrackName(i, fixCase(names[i]));
}
}
/**
* Fixes the case of the supplied string according to our case fixing
* rules.
*/
protected String fixCase (String text)
{
StringTokenizer tok = new StringTokenizer(text);
StringBuffer ntbuf = new StringBuffer();
String excep;
for (int i = 0; tok.hasMoreTokens(); i++) {
String token = tok.nextToken();
if (i > 0) {
ntbuf.append(" ");
}
if ((excep = getException(token)) != null) {
// if this token should be overridden explicitly, do so
ntbuf.append(excep);
} else if (Character.isLowerCase(token.charAt(0))) {
// if the first character is lower case, fix it
ntbuf.append(Character.toUpperCase(token.charAt(0)));
if (token.length() > 1) {
ntbuf.append(token.substring(1));
}
} else {
// otherwise don't mess with it
ntbuf.append(token);
}
}
// report modifications for now
String ntext = ntbuf.toString();
// if (!ntext.equals(text)) {
// System.out.println("Adjusted case '" + text + "' to '" +
// ntext + "'.");
// }
return ntext;
}
/**
* Returns the exception string for this token if there is one
* otherwise null.
*/
protected String getException (String token)
{
// we could toLowerCase() the token and keep all this stuff in a
// hashtable, but the list is small and we'd rather not create a
// zillion objects with all those toLowerCase() calls, so we just
// search the exception list linearly
for (int i = 0; i < OVERRIDE_KEYS.length; i++) {
if (token.equalsIgnoreCase(OVERRIDE_KEYS[i])) {
return OVERRIDE_VALS[i];
}
}
return null;
}
protected void selectDetail (int index)
{
_tmodel.selectDetail(index);
_titText.setText(_tmodel.getTitle());
_artText.setText(_tmodel.getArtist());
}
protected JComboBox _selBox;
protected JTextField _titText;
protected JTextField _artText;
protected JTable _trackTable;
protected DetailTableModel _tmodel;
// used in case fixups
protected static String[] OVERRIDE_KEYS = {
"vs.", "dj", "/"
};
protected static String[] OVERRIDE_VALS = {
"vs.", "DJ", "-"
};
}
@@ -1,193 +0,0 @@
//
// $Id: DetailTableModel.java,v 1.4 2004/01/07 01:57:10 mdb Exp $
package robodj.importer;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.text.Document;
import javax.swing.text.BadLocationException;
import com.samskivert.net.cddb.CDDB;
import robodj.Log;
public class DetailTableModel
extends AbstractTableModel
implements DocumentListener
{
public DetailTableModel (CDDB.Detail[] details, int numTracks)
{
_details = details;
_numTracks = numTracks;
_names = new String[_numTracks];
// copy in the names from the first detail record (or empty
// strings if there is no first detail record)
copyInfo(0);
}
public void selectDetail (int index)
{
// copy the track names from the specified detail record into the
// names array
copyInfo(index);
// fire a data changed event to let the table know what's up
fireTableDataChanged();
}
public String getTitle ()
{
return _title;
}
public String getArtist ()
{
return _artist;
}
// this does not cause the UI displaying the title to update because
// it isn't listening to the model, we're only listening to it
public void setTitle (String title)
{
_title = title;
}
// this does not cause the UI displaying the artist to update because
// it isn't listening to the model, we're only listening to it
public void setArtist (String artist)
{
_artist = artist;
}
// this does cause the track display to update
public void setTrackName (int index, String name)
{
_names[index] = name;
fireTableCellUpdated(index, TITLE_COLUMN);
}
public String[] getTrackNames ()
{
return _names;
}
public void insertUpdate (DocumentEvent e)
{
updateText(e.getDocument());
}
public void removeUpdate (DocumentEvent e)
{
updateText(e.getDocument());
}
public void changedUpdate (DocumentEvent e)
{
updateText(e.getDocument());
}
protected void updateText (Document doc)
{
try {
if (doc.getProperty("name").equals("title")) {
_title = doc.getText(0, doc.getLength());
} else if (doc.getProperty("name").equals("artist")) {
_artist = doc.getText(0, doc.getLength());
}
} catch (BadLocationException ble) {
Log.warning("Can't extract text from text field?!");
Log.logStackTrace(ble);
}
}
protected void copyInfo (int index)
{
if (_details.length > index) {
// extract the artist and title from the combined title
// provided by the detail record
String src = _details[index].title;
int sidx = src.indexOf("/");
if (sidx != -1) {
_artist = src.substring(0, sidx).trim();
_title = src.substring(sidx+1).trim();
} else {
_title = src;
_artist = "Unknown";
}
for (int i = 0; i < _names.length; i++) {
_names[i] = _details[index].trackNames[i];
}
} else {
_title = "Unknown";
_artist = "Unknown";
for (int i = 0; i < _names.length; i++) {
_names[i] = "Track " + (i+1);
}
}
}
public int getRowCount ()
{
return _numTracks;
}
public int getColumnCount ()
{
return COLUMN_NAMES.length;
}
public Object getValueAt (int rowIndex, int columnIndex)
{
switch (columnIndex) {
case TITLE_COLUMN:
return _names[rowIndex];
default:
case 0:
return new Integer(rowIndex+1);
}
}
public String getColumnName (int column)
{
return COLUMN_NAMES[column];
}
public Class getColumnClass (int column)
{
return COLUMN_CLASSES[column];
}
public boolean isCellEditable (int row, int column)
{
return column == TITLE_COLUMN;
}
public void setValueAt (Object value, int row, int column)
{
if (column == TITLE_COLUMN) {
_names[row] = (String)value;
fireTableCellUpdated(row, column);
}
}
protected CDDB.Detail[] _details;
protected String _title;
protected String _artist;
protected String[] _names;
protected int _numTracks;
protected static final String[] COLUMN_NAMES = { "T#", "Title" };
protected static final Class[] COLUMN_CLASSES = {
Integer.class, String.class };
protected static final int TITLE_COLUMN = 1;
}

Some files were not shown because too many files have changed in this diff Show More