Package com.pugh.sockso.music

Source Code of com.pugh.sockso.music.DBCollectionManager

package com.pugh.sockso.music;

import com.pugh.sockso.Constants;
import com.pugh.sockso.Properties;
import com.pugh.sockso.Utils;
import com.pugh.sockso.db.Database;
import com.pugh.sockso.music.indexing.CoverArtIndexer;
import com.pugh.sockso.music.indexing.IndexEvent;
import com.pugh.sockso.music.indexing.IndexListener;
import com.pugh.sockso.music.indexing.Indexer;
import com.pugh.sockso.music.tag.AudioTag;
import com.pugh.sockso.music.tag.InvalidTagException;
import com.pugh.sockso.music.tag.Tag;
import com.pugh.sockso.web.User;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import org.apache.log4j.Logger;

import org.apache.commons.lang3.StringUtils;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

@Singleton
public class DBCollectionManager extends Thread implements CollectionManager, IndexListener {
   
    private static final Logger log = Logger.getLogger( DBCollectionManager.class );

    private final Database db;
    private final Properties p;
    private final List<CollectionManagerListener> listeners;
    private final Indexer indexer;

    /**
     *  constructor
     *
     */

    @Inject
    public DBCollectionManager( final Database db, final Properties p, final Indexer indexer ) {

        this.db = db;
        this.p = p;
        this.indexer = indexer;

        listeners = new ArrayList<CollectionManagerListener>();

    }

    /**
     *  The indexer has detected a change in the tracks we're indexing
     *
     *  @param evt
     *
     */

    public void indexChanged( final IndexEvent evt ) {

        try {

            switch ( evt.getType() ) {

                case UNKNOWN:
                    addFile( evt.getFileId(), evt.getFile() );
                    break;

                case CHANGED:
                    checkTrack( getTrack(evt.getFileId()), evt.getFile() );
                    break;

                case MISSING:
                    removeTrack( evt.getFileId() );
                    break;

                case COMPLETE:
                    removeOrphans();
                    fireCollectionManagerEvent( CollectionManagerListener.UPDATE_COMPLETE, "Collection Updated!" );
                    break;

            }

        }

        catch ( final Throwable t ) {
            log.debug( "indexChanged error on file '" + evt.getFile().getAbsolutePath() + "'", t );
        }

    }

    /**
     *  Extracts a track by ID
     *
     *  @param trackId
     *
     *  @return
     *
     *  @throws java.sql.SQLException
     *
     */

    protected Track getTrack( final int trackId ) throws SQLException {
       
        PreparedStatement st = null;
        ResultSet rs = null;
       
        try {
       
            final String sql = Track.getSelectFromSql() +
                               " where t.id = ? ";

            st = db.prepare( sql );
            st.setInt( 1, trackId );
            rs = st.executeQuery();

            if ( !rs.next() ) {
                throw new SQLException( "Invalid track id" );
            }

            return Track.createFromResultSet( rs );

        }

        finally {
            Utils.close( rs );
            Utils.close( st );
        }
       
    }

    /**
     *  Tries to add an audio file to the collection, creating artist/album info
     *  if required.
     *
     *  @param collectionId
     *  @param file
     *
     *  @throws com.pugh.sockso.music.tag.InvalidTagException
     *  @throws java.io.IOException
     *
     */

    protected void addFile( final int collectionId, final File file ) throws InvalidTagException, IOException {

        final Tag tag = AudioTag.getTag( file );

  log.debug( tag.toString() );

        final int artistId = addArtist( tag.getArtist() );
        int albumArtistId = artistId;

        if ( StringUtils.isBlank(tag.getAlbumArtist()) ) {
            albumArtistId = addArtist( tag.getAlbumArtist() );
        }

        final int albumId  = addAlbum( albumArtistId, tag.getAlbum(), tag.getAlbumYear() );
        final int genreId  = addGenre( tag.getGenre() );
        final int trackId  = addTrack( artistId, albumId, tag.getTrack(),
                tag.getTrackNumber(), file, collectionId, genreId );

        if ( Utils.isFeatureEnabled( p, Constants.COLLMAN_SCAN_COVERS ) ) {

            final BufferedImage coverArt = tag.getCoverArt();
           
            if ( coverArt != null ) {
                addCoverArt( albumArtistId, "ar", coverArt );
                addCoverArt( albumId, "al", coverArt );
                addCoverArt( trackId, "tr", coverArt );
            }
        }

    }

    /**
     *  Adds cover art extracted from the tag for this track
     *
     *  @param itemId
     *  @param itemType
     *  @param coverArt
     *
     */

    protected void addCoverArt( final int itemId, final String itemType, final BufferedImage coverArt ){

        log.debug("Adding Cover Art for itemId: " + itemId + ", itemType: " + itemType);

        // -1 if nothing inserted into db
        if (itemId < 0) {
            log.warn("addCoverArt: itemId param was -1");
            return;
        }
       
        // TODO Would be nice if we had some sort of helper to build a coverId from arbitrary music item types
        String coverId = itemType + itemId;

        final CoverArtIndexer coverArtIndexer = new CoverArtIndexer(p);
        coverArtIndexer.indexCover(new CoverArt( coverId, coverArt ));
    }

    /**
     *  Scans a folder for new files
     *
     *  @param collectionId
     *  @param directory
     *
     */
   
    public void scanDirectory( final int collectionId, final File directory ) {

        try {
            indexer.scanDirectory( collectionId, directory );
        }

        catch ( final Exception e ) {
            log.error( e );
        }

    }
   
    /**
     *  checks the collection for updates.  it actually does 2 scans, one
     *  to check for new files, and the second to check the files in the
     *  collection are still there.
     *
     */
   
    public void checkCollection() {

        indexer.scan();

    }

    /**
     * Re-reads tag information from files
     */
    public void rescanTags() {

        indexer.scan(Indexer.ScanFilter.NONE, Indexer.ScanScope.ALL_FILES);
       
    }

    /**
     *  checks if the album tag information has changed, if it has then updates
     *  the database.
     *
     *  @param artistId
     *  @param tag
     *  @param track
     *
     *  @throws java.sql.SQLException
     *
     */
   
    protected void checkAlbumTagInfo( final int artistId, final Tag tag, final Track track ) throws SQLException {

        // need to ignore case because that's how the DB does it
        if ( !track.getAlbum().getName().equalsIgnoreCase(tag.getAlbum()) ||
             !track.getAlbum().getYear().equalsIgnoreCase(tag.getAlbumYear()) ) {

            ResultSet rs = null;
            PreparedStatement st = null;

            try {

                // if the album has changed, first try and fetch an album
                // for this artist of this new name to tag track to...
                String sql = " select id " +
                             " from albums " +
                             " where name = ? " +
                                 " and artist_id = ? ";

                st = db.prepare( sql );
                st.setString( 1, tag.getAlbum() );
                st.setInt( 2, artistId );
                rs = st.executeQuery();

                final int newAlbumId = rs.next()
                    ? rs.getInt( "id" )
                    : addAlbum( artistId, tag.getAlbum(), tag.getAlbumYear() );

                Utils.close( rs );
                Utils.close( st );
               
                // then update track
                sql = " update tracks " +
                      " set album_id = ? " +
                      " where id = ? ";
               
                st = db.prepare( sql );
                st.setInt( 1, newAlbumId );
                st.setInt( 2, track.getId() );
                st.execute();
               
                Utils.close( rs );
                Utils.close( st );

                sql = " update albums " +
                      " set year = ? " +
                      " where id = ? ";

                st = db.prepare( sql );
                st.setString( 1, tag.getAlbumYear() );
                st.setInt( 2, newAlbumId );
                st.execute();

            }
           
            finally {
                Utils.close( rs );
                Utils.close( st );
            }
               
        }
       
    }

    /**
     *  Checks if the artist information has changed.
     *  If it has changed, then the database is updated and the new artist id is
     *  returned.
     *  Otherwise, the artist id that's returned will be the one from the track
     *  that hasn't changed.
     *
     *  @param tag
     *  @param track
     *
     *  @return
     *
     *  @throws java.sql.SQLException
     *
     */

    protected int checkArtistTagInfo( final Tag tag, final Track track ) throws SQLException {

        // need to ignore case because that's how the DB does it
        if ( !track.getArtist().getName().equalsIgnoreCase(tag.getArtist()) ) {

            PreparedStatement st = null;
            ResultSet rs = null;
           
            try {
           
                // if the artist has changed, first try and fetch an artist
                // of this new name to tag track to...
                String sql = " select id " +
                             " from artists " +
                             " where name = ? ";
               
                st = db.prepare( sql );
                st.setString( 1, tag.getArtist() );
                rs = st.executeQuery();

                final int newArtistId = rs.next()
                    ? rs.getInt("id")
                    : addArtist(tag.getArtist());

                Utils.close( rs );
                Utils.close( st );
               
                // then update track
                sql = " update tracks " +
                      " set artist_id = ? " +
                      " where id = ? ";
               
                st = db.prepare( sql );
                st.setInt( 1, newArtistId );
                st.setInt( 2, track.getId() );
                st.execute();

                Utils.close( rs );
                Utils.close( st );

                sql = " update albums " +
                      " set artist_id = ? " +
                      " where id = ? ";

                st = db.prepare( sql );
                st.setInt( 1, newArtistId );
                st.setInt( 2, track.getAlbum().getId() );
                st.execute();

                return newArtistId;
           
            }
           
            finally {
                Utils.close( rs );
                Utils.close( st );
            }

        }

        // name not changed, but make sure browse_name is up to date
        // @TODO - maybe it'd be better to extract the browse_name with the artist
        // information (in Track), then we can check if it needs changing...
        // is this more unneeded overhead though?
        else {
            updateArtistBrowseName( track.getArtist().getId(), tag.getArtist() );
        }

        return track.getArtist().getId();
       
    }

    /**
     *  Updates the artists browse name from the real name
     *
     *  @param artistId
     *  @param realName
     *
     *  @throws java.sql.SQLException
     *
     */

    protected void updateArtistBrowseName( final int artistId, final String realName ) throws SQLException {

        PreparedStatement st = null;

        try {

            final String browseName = getArtistBrowseName( getArtistPrefixesToRemove(), realName );
            final String sql = " update artists " +
                               " set browse_name = ? " +
                               " where id = ? ";

            st = db.prepare( sql );
            st.setString( 1, browseName );
            st.setInt( 2, artistId );

            st.execute();

        }

        finally {
            Utils.close( st );
        }

    }

    /**
     *  checks if a tracks tag has changed, and updates the database with the
     *  new information if it has.
     *
     *  @param tag
     *  @param track
     *
     *  @throws java.sql.SQLException
     *
     */

    protected void checkTrackTagInfo( final Tag tag, final Track track ) throws SQLException {

        if ( !track.getName().equals(tag.getTrack()) || (track.getNumber() != tag.getTrackNumber()) ) {

            PreparedStatement st = null;

            try {

                final String sql = " update tracks " +
                                   " set name = ?, " +
                                       " track_no = ? " +
                                   " where id = ? ";

                st = db.prepare( sql );
                st.setString( 1, tag.getTrack() );
                st.setInt( 2, tag.getTrackNumber() );
                st.setInt( 3, track.getId() );
                st.execute();

            }
           
            finally {
                Utils.close( st );
            }

        }

    }

    /**
     * checks the genre's tag has changed and updates the database with the
     * new information if it has.
     *
     * @param tag
     * @param track
     *
     * @throws java.sql.SQLException
     *
     */
   
    private void checkGenreTagInfo( final Tag tag, final Track track ) throws SQLException {

        final String genre = ( track.getGenre() == null ? null : track.getGenre().getName() );

        if ( !tag.getGenre().equalsIgnoreCase(genre) ) {

            PreparedStatement st = null;
            ResultSet rs = null;

            try {

                // if the genre has changed, first try and fetch the genre
                // of this new name to tag track to...
                String sql = " select id " +
                             " from genres " +
                             " where name = ? ";

                st = db.prepare( sql );
                st.setString( 1, tag.getGenre() );
                rs = st.executeQuery();

                final int newGenreId = rs.next()
                    ? rs.getInt("id")
                    : addGenre(tag.getGenre());

                Utils.close( rs );
                Utils.close( st );

                // then update the track with the new genre
                sql = " update tracks " +
                      " set genre_id = ? " +
                      " where id = ? ";

                st = db.prepare( sql );
                st.setInt( 1, newGenreId );
                st.setInt( 2, track.getId() );
                st.execute();

            }

            finally {
                Utils.close( rs );
                Utils.close( st );
            }

        }

    }

    /**
     *  checks that a track is up to date with the tag information of it's
     *  file on disk (it may have been edited between updates to the collection)
     *
     *  @param track the track to check
     *  @param file the audio file on disk
     *
     */
   
    private void checkTrack( final Track track, final File file ) {

        try {
           
            final Tag tag = AudioTag.getTag( file );

            // has track info changed?
            checkTrackTagInfo( tag, track );
           
            // has the artist information changed?  if it has we'll get a new
            // artist id, otherwise we'll get the same one as the track is
            // assigned to when we passed in
            final int artistId = checkArtistTagInfo( tag, track );

            // has album info changed?
            checkAlbumTagInfo( artistId, tag, track );

            // has the genre info changed?
            checkGenreTagInfo( tag, track );

        }

        catch ( SQLException e ) { log.debug(e); }
        catch ( InvalidTagException e ) { log.debug(e); }
        catch ( IOException e ) { log.debug(e); }
       
    }
   
    /**
     *  Given an artists name, removes any prefixes we've been asked to.
     *
     *  @param prefixes
     *  @param name
     *
     *  @return
     *
     */

    protected String getArtistBrowseName( final String[] prefixes, final String name ) {

        for ( final String prefix : prefixes ) {
            if ( name.substring(0,prefix.length()).equalsIgnoreCase(prefix) ) {
                return name.substring( prefix.length() );
            }
        }

        return name;

    }

    /**
     *  Returns an array of the artist prefixes we need to remove
     *
     *  @return
     *
     */

    protected String[] getArtistPrefixesToRemove() {

        return p.get( Constants.COLLMAN_ARTIST_REMOVE_PREFIXES ).split( "," );

    }

    /**
     *  removes a track from the collection
     *
     *  @param s statement object to use
     *  @param trackId the track id to remove
     *
     */

    protected void removeTrack( final int trackId ) throws SQLException {

        String sql = " delete from play_log " +
                " where track_id = '" +trackId+ "' ";
        db.update( sql );

        sql = " delete from playlist_tracks " +
                " where track_id = '" +trackId+ "' ";
        db.update( sql );

        sql = " delete from tracks " +
                " where id = '" +trackId+ "' ";
        db.update( sql );
               
    }
   
    /**
     *  allows components to register for collection activity messages
     *
     *  @param listener the listener to register
     *
     */
   
    public void addCollectionManagerListener( final CollectionManagerListener listener ) {

        listeners.add( listener );

    }
   
    /**
     *  signals all listeners that a collection manager event
     *  has just occurred
     *
     *  @param type the event type
     *  @param message the event description
     *
     */
   
    public void fireCollectionManagerEvent( final int type, final String message ) {

        for ( final CollectionManagerListener listener : listeners ) {
            listener.collectionManagerChangePerformed( type, message );
        }

    }

    /**
     *  adds a directory to the database and returns it's new collectionId
     *
     *  @param dir
     *
     *  @return
     *
     *  @throws java.sql.SQLException
     *  @throws java.sql.SQLException
     *
     */
   
    protected int addDirectoryToDb( final File dir ) throws SQLException, SQLException {

        ResultSet rs = null;
        PreparedStatement st = null;
       
        try {

            // add to the database
            String sql = " insert into collection ( path ) " +
                         " values ( ? ) ";
           
            st = db.prepare( sql );
            st.setString( 1, Utils.getPathWithSlash(dir) );
            st.execute();

            Utils.close( st );
           
            // extract new id
            sql = " select max(c.id) as new_id " +
                  " from collection c ";
           
            st = db.prepare( sql );
            rs = st.executeQuery();

            if (!rs.next())
                throw new SQLException("unable to retrieve new id");

            return rs.getInt("new_id");
           
        }
       
        finally {
            Utils.close( rs );
            Utils.close( st );
        }

    }

    /**
     *  adds a directory to the collection
     *
     *  @param dir the directory to add
     *
     */
   
    public int addDirectory( final File dir ) {
       
        try {

            // add to database
            int collectionId = addDirectoryToDb( dir );

            indexer.scanDirectory( collectionId, dir );

            removeOrphans();

            fireCollectionManagerEvent( CollectionManagerListener.UPDATE_COMPLETE, "Update Finished" );

            return collectionId;
           
        }

        catch ( final Exception e ) {
            log.error( "Error adding folder to collection: " + e.getMessage() );
            fireCollectionManagerEvent( CollectionManagerListener.ERROR, e.getMessage() );
        }
       
        return -1;
       
    }
   
    /**
     *  adds an artist to the collection (if it doesn't already
     *  exist) and returns its id
     *
     */

    private int addArtist( String name ) {

        if ( StringUtils.isBlank(name) ) {
            name = "Unknown Artist";
        }

        ResultSet rs = null;
        PreparedStatement st = null;

        try {

            try {
               
                final String browseName = getArtistBrowseName( getArtistPrefixesToRemove(), name );

                st = db.prepare(
                    " insert into artists ( name, date_added, browse_name ) " +
                    " values ( ?, current_timestamp, ? ) "
                );
                st.setString( 1, name );
                st.setString( 2, browseName );
                st.execute();
               
                log.debug( "Added Artist: " + name );
               
            }
            catch ( final Exception e ) {}
            finally {
                Utils.close( st );
            }

            st = db.prepare(
                " select id " +
                " from artists " +
                " where name = ? "
            );
            st.setString( 1, name );
            rs = st.executeQuery();

            if ( rs.next() ) {
                fireCollectionManagerEvent( CollectionManagerListener.ARTIST_ADDED, name );
                return rs.getInt( "id" );
            }
        }
       
        catch ( final Exception e ) {
            log.error( "Error Adding Artist: " + e );
        }

        finally {
            Utils.close( rs );
            Utils.close( st );
            System.gc();
        }
       
        return -1;

    }

    /**
     *  adds an album to the collection (if it doesn't already
     *  exist) and returns its id
     *
     */

    private int addAlbum( final int artistId, String name, String year ) {

        if ( StringUtils.isBlank(name) ) {
            name = "Unknown Album";
        }

        ResultSet rs = null;
        PreparedStatement st = null;

        try {

            try {
               
                st = db.prepare(
                        " insert into albums ( artist_id, name, year, date_added ) " +
                        " values ( ?, ?, ?, current_timestamp ) "
                );
                st.setInt( 1, artistId );
                st.setString( 2, name );
                st.setString(3, year);
                st.execute();
               
                log.debug( "Added Album: " + name + " " + year );
               
            }
            catch ( final Exception e ) {}
            finally {
                Utils.close( st );
            }

            final String sql = " select id " +
                               " from albums " +
                               " where artist_id = ? " +
                                   " and name = ? ";
           
            st = db.prepare( sql );
            st.setInt( 1, artistId );
            st.setString( 2, name );
            rs = st.executeQuery();

            if ( rs.next() ) {
                fireCollectionManagerEvent( CollectionManagerListener.ALBUM_ADDED, name );
                return rs.getInt( "id" );
            }

        }
       
        catch ( final Exception e ) {
            log.error( "Error Adding Album (" + name + "): " + e.getMessage() );
        }
       
        finally {
            Utils.close( rs );
            Utils.close( st );
        }
       
        return -1;

    }


    /**
     *  adds a genre to the collection (if it doesn't already
     *  exist) and returns its id
     *
     */

    private int addGenre( String name ) {

        if ( StringUtils.isBlank(name) ) {
            name = "Unknown Genre";
        }

        ResultSet rs = null;
        PreparedStatement st = null;

        try {

            try {

                st = db.prepare(
                    " insert into genres ( name ) " +
                    " values ( ? ) "
                );
                st.setString( 1, name );
                st.execute();

                log.debug( "Added Genre: " + name );

            }
            catch (Exception e) {}
            finally {
                Utils.close( st );
            }

            st = db.prepare(
                " select id " +
                " from genres " +
                " where name = ? "
            );
            st.setString( 1, name );
            rs = st.executeQuery();

            if ( rs.next() ) {
                fireCollectionManagerEvent( CollectionManagerListener.GENRE_ADDED, name );
                return rs.getInt( "id" );
            }
        }

        catch ( final Exception e ) {
            log.error( "Error Adding Genre: " + e );
        }

        finally {
            Utils.close( rs );
            Utils.close( st );
        }

        return -1;

    }

    /**
     *  adds a track to the collection (if it doesn't already
     *  exist) and returns its id
     *
     */

    private int addTrack( final int artistId, final int albumId, String name,
            final int trackNo, final File file, final int collectionId, final int genreId ) {

        if ( StringUtils.isBlank(name) ) {
            name = "Unknown Track (" + trackNo + ")";
        }

        ResultSet rs = null;
        PreparedStatement st = null;
       
        try {

            try {

                final String sql = " insert into tracks ( artist_id, album_id, name, path, " +
                                   " length, collection_id, date_added, track_no, genre_id ) " +
                                   " values ( ?, ?, ?, ?, 100, ?, current_timestamp, ?, ? ) ";

                st = db.prepare( sql );
                st.setInt( 1, artistId );
                st.setInt( 2, albumId );
                st.setString( 3, name );
                st.setString( 4, file.getAbsolutePath() );
                st.setInt( 5, collectionId );
                st.setInt( 6, trackNo );
                st.setInt( 7, genreId);
                st.execute();

                log.debug( "Added Track: " + name );

            }
            catch ( final Exception e ) {}
           
            finally {
                Utils.close( st );
            }

            final String sql = " select id " +
                " from tracks " +
                " where artist_id = ? " +
                    " and album_id = ? " +
                    " and name = ? ";
           
            st = db.prepare( sql );
            st.setInt( 1, artistId );
            st.setInt( 2, albumId );
            st.setString( 3, name );
            rs = st.executeQuery();

            if ( rs.next() ) {
                fireCollectionManagerEvent( CollectionManagerListener.TRACK_ADDED, name );
                return rs.getInt( "id" );
            }

        }
       
        catch ( final Exception e ) {
            log.error( "Error Adding Track: " + e.getMessage() );
        }
       
        finally {
            Utils.close( rs );
            Utils.close( st );
        }
       
        return -1;
       
    }
   
    /**
     *  removes a directory from the collection
     *
     *  @param path the path of the directory to remove
     *
     */
   
    public boolean removeDirectory( final String path ) {

        ResultSet rs = null;
        PreparedStatement st = null;

        try {

            // first we need to get the collection id
            String sql = " select id " +
                         " from collection c " +
                         " where path = ? ";
            st = db.prepare( sql );
            st.setString( 1, Utils.getPathWithSlash(path) );
            rs = st.executeQuery();

            if ( rs.next() ) {

                final int collectionId = rs.getInt( "id" );

                Utils.close( rs );
                Utils.close( st );
               
                // remove items from the play_log
                sql = " delete from play_log " +
                        " where track_id in ( " +
                            " select id " +
                            " from tracks t " +
                            " where collection_id = ? " +
                        " ) ";
                st = db.prepare( sql );
                st.setInt( 1, collectionId );
                st.execute();
               
                Utils.close( st );

                // remove tracks from playlists
                sql = " delete from playlist_tracks " +
                        " where track_id in ( select id " +
                            " from tracks " +
                            " where collection_id = ? ) ";
                st = db.prepare( sql );
                st.setInt( 1, collectionId );
                st.execute();
               
                Utils.close( st );

                // remove tracks from the collection
                sql = " delete from tracks " +
                        " where collection_id = ? ";
                st = db.prepare( sql );
                st.setInt( 1, collectionId );
                st.execute();
               
                Utils.close( st );

                // remove the collection
                sql = " delete from collection " +
                        " where id = ? ";
                st = db.prepare( sql );
                st.setInt( 1, collectionId );
                st.execute();

                Utils.close( st );

                removeOrphans();
                fireCollectionManagerEvent( CollectionManagerListener.UPDATE_COMPLETE, "Directory Removed" );

                return true;

            }           
           
        }
       
        catch ( final SQLException e ) {
            log.error( e.getMessage() );
        }

        finally {
            Utils.close( rs );
            Utils.close( st );
        }
       
        return false;
       
    }

    /**
     * Clean up unreferenced artists, albums, genres from database
     *
     * @throws SQLException
     */
    protected void removeOrphans() throws SQLException {

        removeOrphanedArtists();
        removeOrphanedAlbums();
        removeOrphanedGenres();

    }

    /**
     *  Removes any artists from the collection that don't
     *  have any tracks associated with them
     *
     *  @throws SQLException
     *
     */
   
    protected void removeOrphanedArtists() throws SQLException {

        // remove any artists left without tracks OR albums
        // (artist can be an "album artist" and have zero tracks)
        String sql = " delete from artists " +
                     " where id not in ( select artist_id from albums ) " +
                     "   and id not in ( select artist_id from tracks ) ";

        db.update( sql );

    }

    /**
     *  Removes any albums from the collection that don't
     *  have any tracks associated with them
     *
     *  @throws SQLException
     *
     */

    protected void removeOrphanedAlbums() throws SQLException {

        // remove any albums left without tracks
        String sql = " delete from albums " +
                     " where id not in ( select album_id " +
                                       " from tracks ) ";

        db.update( sql );

    }

    /**
     *  removes any albums from the collection that don't
     *  have any tracks associated with them
     *
     *  @throws SQLException
     *
     */

    protected void removeOrphanedGenres() throws SQLException {

        // remove any genres left without tracks
        String sql = " delete from genres " +
                     " where id not in ( select genre_id " +
                                       " from tracks ) ";
        db.update( sql );

    }

    public int savePlaylist( final String name, final Track[] tracks ) {

        return savePlaylist( name, tracks, null );
       
    }

    /**
     *  saves a playlist for a user to the collection
     *
     *  @param name the name of the playlist
     *  @param tracks track ids for the playlist
     *
     */
   
    public int savePlaylist( final String name, final Track[] tracks, final User user ) {
       
        ResultSet rs = null;
        PreparedStatement st = null;

        try {
           
            int playlistId = -1;
           
            // see if old playlist exists

            String sql = " select id " +
                         " from playlists p " +
                         " where name = ? ";
            st = db.prepare( sql );
            st.setString( 1, name );
            rs = st.executeQuery();
            if ( rs.next() )
                removePlaylist( rs.getInt("id") );
           
            Utils.close( rs );
            Utils.close( st );

            // create playlist

            sql = " insert into playlists ( name, user_id, date_created, date_modified ) " +
                    " values ( ?, ?, current_timestamp, current_timestamp ) ";
            st = db.prepare( sql );
            st.setString( 1, name );
            if ( user == null )
                st.setNull( 2, Types.INTEGER );
            else
                st.setInt( 2, user.getId() );
            st.execute();

            Utils.close( rs );
            Utils.close( st );
           
            // fetch new id
           
            sql = " select max(p.id) as new_id " +
                  " from playlists p ";
            st = db.prepare( sql );
            rs = st.executeQuery();
            if ( rs.next() )
                playlistId = rs.getInt( "new_id" );
            else
                throw new SQLException( "couldn't get new playlist id" );
           
            Utils.close( rs );
            Utils.close( st );

            // then add tracks to playlist

            sql = " insert into playlist_tracks ( playlist_id, track_id ) " +
                    " values ( ?, ? ) ";
            st = db.prepare( sql );

            for ( final Track track : tracks ) {
           
                st.setInt( 1, playlistId );
                st.setInt( 2, track.getId() );
                st.execute();
               
            }

            fireCollectionManagerEvent( CollectionManagerListener.PLAYLISTS_CHANGED, name  );
           
            return playlistId;

        }
       
        catch ( final SQLException e ) {
            log.error( e.getMessage() );
        }
       
        finally {
            Utils.close( rs );
            Utils.close( st );
        }
       
        return -1;

    }
   
    /**
     *  tries to remove a playlist from the collection, returns a boolean
     *  indicating if it was successful
     *
     *  @param id id of playlist to remove
     *  @return boolean indicating success
     *
     */
   
    public boolean removePlaylist( final int id ) {

        PreparedStatement st = null;
       
        try {

            String sql = " delete from playlist_tracks " +
                         " where playlist_id = ? ";
           
            st = db.prepare( sql );
            st.setInt( 1, id );
            st.execute();

            Utils.close( st );

            sql = " delete from playlists " +
                  " where id = ? ";
            st = db.prepare( sql );
            st.setInt( 1, id );
            st.execute();

            fireCollectionManagerEvent( CollectionManagerListener.PLAYLISTS_CHANGED, "Playlist removed"  );
           
        }
       
        catch ( final SQLException e ) {
            log.error( e );
            return false;
        }

        finally {
            Utils.close( st );
        }
       
        return true;
       
    }
   
}
TOP

Related Classes of com.pugh.sockso.music.DBCollectionManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.