Package co.arcs.groove.basking.task

Source Code of co.arcs.groove.basking.task.DownloadSongTask

package co.arcs.groove.basking.task;

import com.belladati.httpclientandroidlib.HttpResponse;
import com.google.common.eventbus.EventBus;
import com.mpatric.mp3agic.ID3v2;
import com.mpatric.mp3agic.ID3v22Tag;
import com.mpatric.mp3agic.ID3v23Tag;
import com.mpatric.mp3agic.Mp3File;
import com.mpatric.mp3agic.NotSupportedException;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Semaphore;

import co.arcs.groove.basking.SyncService;
import co.arcs.groove.basking.Utils;
import co.arcs.groove.basking.event.Events.DownloadSongFinishedEvent;
import co.arcs.groove.basking.event.Events.DownloadSongProgressChangedEvent;
import co.arcs.groove.basking.event.Events.DownloadSongStartedEvent;
import co.arcs.groove.thresher.Client;
import co.arcs.groove.thresher.Song;

public class DownloadSongTask implements Task<Song> {

    private final EventBus bus;
    private final Client client;
    private final Song song;
    private final File syncFile;
    private final File tempPath;
    private final Semaphore concurrentJobsSemaphore;

    private static final int INPUT_BUFFER_LEN = 1024 * 64;

    /**
     * @param targetFile
     *         The file in which to store the downloaded song.
     * @param tempPath
     *         A directory in which the task can create temporary files.
     * @param concurrentJobsSemaphore
     *         A semaphore the task will acquire and hold while downloading the song. This is used
     *         to control the number of concurrently running download tasks.
     */
    public DownloadSongTask(EventBus bus,
            Client client,
            Song song,
            File targetFile,
            File tempPath,
            Semaphore concurrentJobsSemaphore) {
        this.bus = bus;
        this.client = client;
        this.song = song;
        this.syncFile = targetFile;
        this.tempPath = tempPath;
        this.concurrentJobsSemaphore = concurrentJobsSemaphore;
    }

    @Override
    public Song call() throws Exception {

        concurrentJobsSemaphore.acquire();

        try {
            bus.post(new DownloadSongStartedEvent(this, song));

            File tempFile = new File(tempPath,
                    syncFile.getName() + SyncService.TEMP_FILE_EXTENSION_1);
            File tempFile2 = new File(tempPath,
                    syncFile.getName() + SyncService.TEMP_FILE_EXTENSION_2);

            // Download file
            InputStream is = null;
            FileOutputStream os = null;
            try {
                HttpResponse response = client.getStreamResponse(song);
                is = new BufferedInputStream(response.getEntity().getContent(), INPUT_BUFFER_LEN);
                os = new FileOutputStream(tempFile);

                bus.post(new DownloadSongProgressChangedEvent(this, song, 0, 1));

                byte[] buffer = new byte[INPUT_BUFFER_LEN];

                long len = response.getEntity().getContentLength();
                int read;
                int readTotal = 0;
                float lastReportedProgress = 0;

                while ((read = is.read(buffer)) != -1) {
                    os.write(buffer, 0, read);
                    readTotal += read;

                    // Only emit events for >1% change
                    float newProgress = (float) readTotal / len;
                    if (((newProgress - 0.01f) >= lastReportedProgress) || newProgress == 1.0f) {
                        bus.post(new DownloadSongProgressChangedEvent(this,
                                song,
                                readTotal,
                                (int) len));
                        lastReportedProgress = newProgress;
                    }

                    // Bail out if the thread was interrupted inside this loop
                    if (Thread.currentThread().isInterrupted()) {
                        throw new InterruptedException();
                    }
                }
                os.flush();
                os.getFD().sync();
            } finally {
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
            }

            // Remove id3v1 tag
            Mp3File mp3File = new Mp3File(tempFile.getAbsolutePath());
            if (mp3File.hasId3v1Tag()) {
                mp3File.removeId3v1Tag();
            }

            // Get/create id3v2 tag
            ID3v2 id3v2Tag;
            if (mp3File.hasId3v2Tag()) {
                id3v2Tag = mp3File.getId3v2Tag();
            } else {
                id3v2Tag = new ID3v23Tag();
            }
            Exception err = null;
            while (true) {
                // Try saving twice; once with old tag data, and again after
                // discarding corrupt data and starting over
                try {
                    id3v2Tag.setTitle(song.getName());
                    id3v2Tag.setArtist(song.getArtistName());
                    id3v2Tag.setAlbum(song.getAlbumName());
                    id3v2Tag.setYear(song.getYear() + "");
                    Utils.encodeId(song.getId(), id3v2Tag);
                    mp3File.setId3v2Tag(id3v2Tag);
                    mp3File.save(tempFile2.getAbsolutePath());
                    break;
                } catch (NotSupportedException e) {
                    if (err != null) {
                        e.initCause(err);
                        throw e;
                    } else {
                        // Discard old tag if obsolete
                        id3v2Tag = new ID3v22Tag();
                        err = e;
                    }
                }
            }

            // Delete temp 1 file
            if (!tempFile.delete()) {
                throw new IOException("Failed to delete temp file: " + tempFile.getAbsolutePath());
            }

            // Move temp 2 file to sync directory
            if (!tempFile2.renameTo(syncFile)) {
                throw new IOException("Failed to move temp file: " + tempFile2.getAbsolutePath());
            }

            bus.post(new DownloadSongFinishedEvent(this, song));
        } finally {
            concurrentJobsSemaphore.release();
        }

        return song;
    }
}
TOP

Related Classes of co.arcs.groove.basking.task.DownloadSongTask

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.