Changeset 93

Show
Ignore:
Timestamp:
01/03/08 00:49:25 (11 months ago)
Author:
chris
Message:

chages to get the parser work properly for shuffles. The issue solved
is the track ordering. The iTunesSD file is now used on shuffles (it
stores the order.)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/main/org/lastpod/ModelImpl.java

    r90 r93  
    2424import org.lastpod.parser.TrackItemParser; 
    2525 
    26 import org.lastpod.util.ItunesStatsFilter; 
    2726import org.lastpod.util.MiscUtilities; 
    28  
    29 import java.io.File; 
    3027 
    3128import java.util.ArrayList; 
     
    10198        History.getInstance(iTunesPath); 
    10299 
     100        boolean isShuffle = ItunesStatsParser.isIpodShuffle(iTunesPath); 
     101 
    103102        ItunesDbParser itunesDbParser = 
    104             new ItunesDbParser(iTunesPath, parseVariousArtists, splitVariousArtistStrings); 
    105  
    106         /* Defaults to the parser for non-shuffle iPods. */ 
    107         TrackItemParser playCountsParser = new PlayCountsParser(iTunesPath, parseMultiPlayTracks); 
    108  
    109         /* Checks for the "iTunesStats" file.  If it exists, switch to the iPod 
    110          * shuffle parser. */ 
    111         File file = new File(iTunesPath); 
    112         File[] itunesStatsFiles = file.listFiles(new ItunesStatsFilter()); 
    113  
    114         if ((itunesStatsFiles != null) && (itunesStatsFiles.length != 0)) { 
     103            new ItunesDbParser(iTunesPath, parseVariousArtists, splitVariousArtistStrings, isShuffle); 
     104 
     105        TrackItemParser playCountsParser = null; 
     106 
     107        /* If the iPod is a Shuffle, use the iPod shuffle parser. Otherwise 
     108         * use the non-shuffle parser. */ 
     109        if (isShuffle) { 
    115110            playCountsParser = new ItunesStatsParser(iTunesPath, parseMultiPlayTracks); 
     111        } else { 
     112            playCountsParser = new PlayCountsParser(iTunesPath, parseMultiPlayTracks); 
    116113        } 
    117114 
  • trunk/src/main/org/lastpod/action/DeletePlayCounts.java

    r89 r93  
    2222import org.lastpod.UI; 
    2323 
    24 import org.lastpod.util.ItunesStatsFilter; 
     24import org.lastpod.parser.ItunesStatsParser; 
    2525 
    2626import java.awt.event.ActionEvent; 
     
    9191        playCountsFile = new File(iTunesPath + "Play Counts"); 
    9292 
    93         /* Checks for the "iTunesStats" file.  If it exists, switch to the iPod 
    94          * shuffle file. */ 
    95         File file = new File(iTunesPath); 
    96         File[] itunesStatsFiles = file.listFiles(new ItunesStatsFilter()); 
    97  
    98         if ((itunesStatsFiles != null) && (itunesStatsFiles.length != 0)) { 
     93        /* If the iPod is a Shuffle, switch to the shuffle delete logic. */ 
     94        if (ItunesStatsParser.isIpodShuffle(iTunesPath)) { 
    9995            playCountsFile = new File(iTunesPath + "iTunesStats"); 
    10096            putValue(SHORT_DESCRIPTION, "Removes the iTunesStats file from the iPod shuffle."); 
  • trunk/src/main/org/lastpod/parser/ItunesDbParser.java

    r92 r93  
    2929import java.io.InputStream; 
    3030 
     31import java.math.BigInteger; 
     32 
    3133import java.util.ArrayList; 
     34import java.util.HashMap; 
    3235import java.util.List; 
     36import java.util.Map; 
    3337 
    3438/** 
     
    4549 
    4650    /** 
     51     * The location of the iTunesSD file. 
     52     */ 
     53    private String iTunesSdFile; 
     54 
     55    /** 
    4756     * Stores a boolean value that will be passed into <code>TrackItem</code>. 
    4857     */ 
     
    5362     */ 
    5463    String[] variousArtistsStrings; 
     64 
     65    /** 
     66     * Stores <code>true</code> if this iTunesDB is for an iPod shuffle. 
     67     */ 
     68    boolean isShuffle = false; 
    5569 
    5670    /** 
     
    7084     * @param variousArtistsStrings  A String array containing the various artist 
    7185     * strings that should be parsed. 
     86     * @param isShuffle  <code>true</code> if this iTunesDB is for an iPod shuffle. 
    7287     */ 
    7388    public ItunesDbParser(String iTunesPath, boolean parseVariousArtists, 
    74         String[] variousArtistsStrings) { 
     89        String[] variousArtistsStrings, boolean isShuffle) { 
    7590        if (!iTunesPath.endsWith(File.separator)) { 
    7691            iTunesPath += File.separator; 
     
    7893 
    7994        this.iTunesFile = iTunesPath + "iTunesDB"; 
     95        this.iTunesSdFile = iTunesPath + "iTunesSD"; 
    8096        this.parseVariousArtists = parseVariousArtists; 
    8197        this.variousArtistsStrings = variousArtistsStrings; 
     98        this.isShuffle = isShuffle; 
    8299    } 
    83100 
     
    95112            itunesBufferedIn = new BufferedInputStream(itunesFileIn, 65535); 
    96113 
    97             return parseitunesdb(itunesBufferedIn); 
     114            List trackList = parseitunesdb(itunesBufferedIn); 
     115 
     116            if (!isShuffle) { 
     117                return trackList; 
     118            } else { 
     119                return readItunesSdAndReorderList(trackList); 
     120            } 
    98121        } catch (IOException e) { 
    99122            throw new RuntimeException("Error reading iTunes Database"); 
     
    240263 
    241264    /** 
     265     * Reads the iTunesSD file and uses the ordering in this file to reorder 
     266     * the track list. 
     267     * @param trackList  The track list from the iTunesDB 
     268     * @return  A new <code>java.util.List</code> that is ordered per the 
     269     * iTunesSD order. 
     270     * @throws IOException  Thrown if I/O errors occur. 
     271     */ 
     272    private List readItunesSdAndReorderList(List trackList) 
     273            throws IOException { 
     274        InputStream itunesSdFileIn = null; 
     275        InputStream itunesSdBufferedIn = null; 
     276 
     277        try { 
     278            itunesSdFileIn = new FileInputStream(iTunesSdFile); 
     279            itunesSdBufferedIn = new BufferedInputStream(itunesSdFileIn, 65535); 
     280 
     281            /* Converts the trackList into a Map. */ 
     282            Map trackMap = new HashMap(); 
     283            TrackItem track = null; 
     284 
     285            for (int i = 0; i < trackList.size(); i++) { 
     286                track = (TrackItem) trackList.get(i); 
     287                trackMap.put(track.getLocation(), track); 
     288            } 
     289 
     290            List orderedTrackList = new ArrayList(); 
     291 
     292            byte[] threeBytes = new byte[3]; 
     293 
     294            itunesSdBufferedIn.read(threeBytes); 
     295 
     296            int numentries = (new BigInteger(threeBytes)).intValue(); 
     297 
     298            IoUtils.skipFully(itunesSdBufferedIn, 15); //skip rest of header 
     299            assert (numentries == trackList.size()); 
     300 
     301            for (int i = 0; i < (numentries - 1); i++) { 
     302                itunesSdBufferedIn.mark(1048576); //save beginning of entry location 
     303 
     304                itunesSdBufferedIn.read(threeBytes); 
     305 
     306                int entrylen = (new BigInteger(threeBytes)).intValue(); 
     307 
     308                IoUtils.skipFully(itunesSdBufferedIn, 30); 
     309 
     310                byte[] data = new byte[522]; 
     311                itunesSdBufferedIn.read(data); 
     312 
     313                /* Filename should have : characters instead of / characters. */ 
     314                String filename = new String(data, "UTF-16LE").replace('/', ':').trim(); 
     315 
     316                orderedTrackList.add(trackMap.get(filename)); 
     317 
     318                itunesSdBufferedIn.reset(); 
     319                IoUtils.skipFully(itunesSdBufferedIn, entrylen); 
     320            } 
     321 
     322            return orderedTrackList; 
     323        } finally { 
     324            IoUtils.cleanup(itunesSdFileIn, null); 
     325            IoUtils.cleanup(itunesSdBufferedIn, null); 
     326        } 
     327    } 
     328 
     329    /** 
    242330     * Does nothing for this implementation. 
    243331     * @param trackList  Does nothing for this implementation. 
  • trunk/src/main/org/lastpod/parser/ItunesStatsParser.java

    r91 r93  
    2222 
    2323import org.lastpod.util.IoUtils; 
     24import org.lastpod.util.ItunesStatsFilter; 
    2425 
    2526import java.io.BufferedInputStream; 
     
    113114            playCountsBufferedIn = new BufferedInputStream(playCountsFileIn, 65535); 
    114115 
    115             return parseitunesStats(playCountsBufferedIn); 
     116            List trackList = parseitunesStats(playCountsBufferedIn); 
     117 
     118            return manufactureLastPlayed(trackList); 
    116119        } catch (IOException e) { 
    117120            String errorMsg = 
     
    145148        IoUtils.skipFully(itunesStatsistream, 3); //skip rest of header 
    146149 
    147         Calendar calendar = Calendar.getInstance(); 
    148  
    149150        for (int i = 0; i < (numentries - 1); i++) { 
    150151            itunesStatsistream.mark(1048576); //save beginning of entry location 
     
    164165                TrackItem temptrack = (TrackItem) trackList.get(i); 
    165166                temptrack.setPlaycount(playcount); 
    166                 calendar.add(Calendar.SECOND, -(int) temptrack.getLength()); 
    167                 temptrack.setLastplayed(calendar.getTimeInMillis() / 1000); 
    168  
    169167                recentPlays.add(trackList.get(i)); 
    170168 
     
    173171 
    174172                    for (long j = 0; j < numberToManufacture; j++) { 
    175                         temptrack = manufactureTrack(temptrack, calendar); 
     173                        temptrack = manufactureTrack(temptrack); 
    176174                        recentPlays.add(temptrack); 
    177175                    } 
     
    193191     * @return  A manufactured <code>TrackItem</code>. 
    194192     */ 
    195     private TrackItem manufactureTrack(TrackItem temptrack, Calendar calendar) { 
     193    private TrackItem manufactureTrack(TrackItem temptrack) { 
    196194        TrackItem manufacturedTrack = new TrackItem(temptrack); 
    197         calendar.add(Calendar.SECOND, -(int) manufacturedTrack.getLength()); 
    198         manufacturedTrack.setLastplayed(calendar.getTimeInMillis() / 1000); 
    199  
    200195        manufacturedTrack.setPlaycount(1); 
    201196        temptrack.setPlaycount(1); 
     
    203198        return manufacturedTrack; 
    204199    } 
     200 
     201    /** 
     202     * Manufactures the last played times for all the track items. 
     203     * @param trackItems  The list of track items to modify. 
     204     * @return  The modified list of track items. 
     205     */ 
     206    private List manufactureLastPlayed(List trackItems) { 
     207        Calendar calendar = Calendar.getInstance(); 
     208        TrackItem temptrack = null; 
     209 
     210        for (int i = trackItems.size() - 1; i >= 0; i--) { 
     211            temptrack = (TrackItem) trackItems.get(i); 
     212            calendar.add(Calendar.SECOND, -(int) temptrack.getLength()); 
     213            temptrack.setLastplayed(calendar.getTimeInMillis() / 1000); 
     214        } 
     215 
     216        return trackItems; 
     217    } 
     218 
     219    /** 
     220     * Utility function to determine if the iTunesPath is that of an iPod shuffle. 
     221     * @param iTunesPath  The path to the iTunes_Control directory. 
     222     * @return  <code>true</code> if the iPod is a Shuffle. 
     223     */ 
     224    public static boolean isIpodShuffle(String iTunesPath) { 
     225        /* Checks for the "iTunesStats" file.  If it exists, switch to the iPod 
     226         * shuffle file. */ 
     227        File file = new File(iTunesPath); 
     228        File[] itunesStatsFiles = file.listFiles(new ItunesStatsFilter()); 
     229 
     230        return (itunesStatsFiles != null) && (itunesStatsFiles.length != 0); 
     231    } 
    205232}