Package com.groovesquid.service

Source Code of com.groovesquid.service.DownloadService$DownloadTask

package com.groovesquid.service;

import com.google.gson.Gson;
import com.groovesquid.Config.FileExists;
import com.groovesquid.Grooveshark;
import com.groovesquid.Main;
import com.groovesquid.model.*;
import com.groovesquid.util.Utils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.protocol.HTTP;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static java.lang.String.format;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FilenameUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;

public class DownloadService {

    private final static Logger log = Logger.getLogger(Main.class.getName());

    private final ExecutorService executorService;
    private final ExecutorService executorServiceForPlay;
    private final List<DownloadTask> currentlyRunningDownloads = new ArrayList<DownloadTask>();
    private final FilenameSchemeParser filenameSchemeParser;

    private long nextSongMustSleepUntil;

    public DownloadService() {
        this.executorService = Executors.newFixedThreadPool(Main.getConfig().getMaxParallelDownloads());
        this.executorServiceForPlay = Executors.newFixedThreadPool(1);
        this.filenameSchemeParser = new FilenameSchemeParser();
    }

    public FilenameSchemeParser getFilenameSchemeParser() {
        return filenameSchemeParser;
    }

    public synchronized Track download(Song song) {
        return download(song, null);
    }

    public synchronized Track download(Song song, DownloadListener downloadListener) {
        File downloadDir = new File(Main.getConfig().getDownloadDirectory());
        File file = new File(downloadDir, filenameSchemeParser.parse(song, Main.getConfig().getFileNameScheme()));
       
        if(file.exists()) {
            if(Main.getConfig().getFileExists() == FileExists.OVERWRITE.ordinal()) {
               
               
            } else if(Main.getConfig().getFileExists() == FileExists.RENAME.ordinal()) {
                int i = 1;
                String fileName = FilenameUtils.removeExtension(file.getAbsolutePath());
                while(file.exists()) {
                    file = new File(fileName + "_" + i + ".mp3");
                    if(i >= 10) {
                        break;
                    }
                    i++;
                }
               
            } else if(Main.getConfig().getFileExists() == FileExists.DO_NOTHING.ordinal()) {
               
            }
        }
       
        Store store = new FileStore(file, downloadDir);
        return download(song, store, downloadListener, false);
    }

    public synchronized Track downloadToMemory(Song song) {
        return downloadToMemory(song, null);
    }

    public synchronized Track downloadToMemory(Song song, DownloadListener downloadListener) {
        Store store = new MemoryStore(song.toString());
        return download(song, store, downloadListener, true);
    }

    private Track download(Song song, Store store, DownloadListener downloadListener, boolean forPlay) {
        song.setDownloaded(true);
        Track track = new Track(song, store);
        int additionalAbortDelay = 0;
        boolean downloadWasInterrupted = cancelDownload(track, true);
        if (downloadWasInterrupted && !forPlay)
            additionalAbortDelay += 5000;
        additionalAbortDelay += Math.max(nextSongMustSleepUntil - System.currentTimeMillis(), 0);
        DownloadTask downloadTask = new DownloadTask(track, additionalAbortDelay, downloadListener);
        currentlyRunningDownloads.add(downloadTask);
        if (forPlay) {
            executorServiceForPlay.submit(downloadTask);
        } else {
            executorService.submit(downloadTask);
        }
        nextSongMustSleepUntil = Math.max(System.currentTimeMillis(), nextSongMustSleepUntil + 1000);
        return track;
    }
   
    public synchronized boolean cancelDownload(Track track, boolean deleteStore) {
        return cancelDownload(track, deleteStore, false);
    }

    public synchronized boolean cancelDownload(Track track, boolean deleteStore, boolean safeDelete) {
        DownloadTask downloadTask = findDownloadTask(track);
        if(safeDelete) {
            if(downloadTask == null) {
                downloadTask = new DownloadTask(track, 0, null);
                currentlyRunningDownloads.add(downloadTask);
            }
        }
        return cancelDownload(downloadTask, deleteStore);
    }

    private synchronized boolean cancelDownload(DownloadTask downloadTask, boolean deleteStore) {
        boolean downloadWasInterrupted = false;
        if (downloadTask != null) {
            currentlyRunningDownloads.remove(downloadTask);
            downloadWasInterrupted = downloadTask.abort();
            if (deleteStore) {
                if(downloadTask.track.getStore() == null) {
                    File downloadDir = new File(Main.getConfig().getDownloadDirectory());
                    Store store = new FileStore(new File(downloadTask.track.getPath()), downloadDir);
                    downloadTask.track.setStore(store);
                }
                downloadTask.track.getStore().deleteStore();
            }
            downloadTask.track.setStatus(Track.Status.CANCELLED);
            downloadTask.fireDownloadStatusChanged();
        }
        return downloadWasInterrupted;
    }

    private DownloadTask findDownloadTask(Track track) {
        for (DownloadTask downloadTask : currentlyRunningDownloads) {
            if (downloadTask.track.getStore().isSameLocation(track.getStore())) {
                return downloadTask;
            }
        }
        return null;
    }

    public void shutdown() {
        executorService.shutdownNow();
        executorServiceForPlay.shutdownNow();
        ArrayList<DownloadTask> downloadsCopy = new ArrayList<DownloadTask>(currentlyRunningDownloads);
        for (DownloadTask downloadTask : downloadsCopy) {
            cancelDownload(downloadTask, true);
        }
    }
   
    public boolean areCurrentlyRunningDownloads() {
        return currentlyRunningDownloads.size() > 0;
    }


    private class DownloadTask implements Runnable {
        private final Track track;
        private final int initialDelay;
        private final DownloadListener downloadListener;
        private volatile HttpPost httpPost;
        private volatile boolean aborted;

        public DownloadTask(Track track, int initialDelay, DownloadListener downloadListener) {
            this.track = track;
            this.initialDelay = initialDelay;
            this.downloadListener = downloadListener;
        }
       
        class Response {
            private HashMap<String, Object> header;
            private HashMap<String, Object> result;
            private HashMap<String, Object> fault;

            public Response(HashMap<String, Object> header, HashMap<String, Object> result) {
                this.header = header;
                this.result = result;
            }

            public HashMap getHeader() {
                return this.header;
            }

            public HashMap<String, Object> getResult() {
                return this.result;
            }

            public HashMap<String, Object> getFault() {
                return this.fault;
            }
        }

        public void run() {
            try {
                if (track.getStatus() == Track.Status.CANCELLED)
                    return;
                Thread.sleep(initialDelay);
                if (track.getStatus() == Track.Status.CANCELLED)
                    return;
               
                track.setStatus(Track.Status.INITIALIZING);
                fireDownloadStatusChanged();
               
                Gson gson = new Gson();

                Response response = gson.fromJson(Grooveshark.sendRequest("getStreamKeyFromSongIDEx", new HashMap(){{
                    put("country", Grooveshark.getCountry());
                    put("mobile", "false");
                    put("prefetch", "false");
                    put("songID", track.getSong().getId());
                    put("type", "0");
                }}), Response.class);

                if(response.getFault() != null && response.getFault().get("code") == "256") {
                    log.info("INVALID TOKEN, BITCH");
                }

                HashMap<String, Object> result = response.getResult();

                String downloadUrl = "http://" + result.get("ip").toString() + "/stream.php";
                final String streamKey = result.get("streamKey").toString();
                final String streamServerID = result.get("streamServerID").toString();
                long uSecs = Long.valueOf(result.get("uSecs").toString());

                track.setStatus(Track.Status.DOWNLOADING);
                track.setStartDownloadTime(System.currentTimeMillis());
                if ((track.getSong().getDuration() == null || track.getSong().getDuration() <= 0.0) && uSecs > 0) {
                    track.getSong().setDuration(uSecs / 1000000.0);
                }
                fireDownloadStatusChanged();
               
                download(downloadUrl, streamKey);
                track.setStatus(Track.Status.FINISHED);
                fireDownloadStatusChanged();
                log.info("finished download track " + track);

                HashMap<String, Object> result2 = gson.fromJson(Grooveshark.sendRequest("markSongDownloadedEx", new HashMap(){{
                    put("songID", track.getSong().getId());
                    put("streamKey", streamKey);
                    put("streamServerID", streamServerID);
                }}), Response.class).getResult();
                if(!result2.get("Return").toString().equalsIgnoreCase("true")) {
                    log.severe("markSongDownloadedEx did not return true");
                }

            } catch (Exception ex) {
                if (aborted || ex instanceof InterruptedException) {
                    log.info("cancel download by request: " + track);
                    track.setStatus(Track.Status.CANCELLED);
                } else {
                    log.log(Level.SEVERE, "error download track " + track, ex);
                    track.setStatus(Track.Status.ERROR);
                    //track.setFault(ex);
                }
                track.getStore().deleteStore();
                fireDownloadStatusChanged();
            } finally {
                track.setStopDownloadTime(System.currentTimeMillis());
                synchronized (DownloadService.this) {
                    currentlyRunningDownloads.remove(this);
                }
                synchronized (this) {
                    httpPost = null;
                }
                fireDownloadStatusChanged();
            }
        }

        public synchronized boolean abort() {
            if (httpPost != null) {
                aborted = true;
                httpPost.abort();
                return true;
            }
            return false;
        }

        private void download(String url, String streamKey) throws IOException {
            httpPost = new HttpPost(url);
            httpPost.setHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded");
            httpPost.setHeader(HTTP.CONN_KEEP_ALIVE, "300");
            httpPost.setEntity(new StringEntity("streamKey=" + streamKey));
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            if(Main.getConfig().getProxyHost() != null && Main.getConfig().getProxyPort() != null) {
                httpClientBuilder.setProxy(new HttpHost(Main.getConfig().getProxyHost(), Main.getConfig().getProxyPort()));
            }
            HttpClient httpClient = httpClientBuilder.build();
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            OutputStream outputStream = null;
            try {
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();
                if (statusCode == HttpStatus.SC_OK) {
                    track.setTotalBytes(httpEntity.getContentLength());
                    Store store = track.getStore();
                    OutputStream storeOutputStream = store.getOutputStream();
                    outputStream = new MonitoredOutputStream(storeOutputStream);
                    InputStream instream = httpEntity.getContent();
                    byte[] buf = new byte[10240];
                    int l;
                    while ((l = instream.read(buf)) != -1) {
                        outputStream.write(buf, 0, l);
                    }
                    // need to close immediately otherwise we cannot write ID tags
                    outputStream.close();
                    outputStream = null;
                    // write ID tags
                    store.writeTrackInfo(track);
                } else {
                    throw new HttpResponseException(statusCode,
                        format("%s: %d %s", url, statusCode, statusLine.getReasonPhrase()));
                }
            } finally {
                close(httpEntity);
                Utils.closeQuietly(outputStream, track.getStore().getDescription());
            }
        }

        private void fireDownloadStatusChanged() {
            if (downloadListener != null)
                downloadListener.statusChanged(track);
        }

        private void fireDownloadBytesChanged() {
            if (downloadListener != null)
                downloadListener.downloadedBytesChanged(track);
        }

        private void close(HttpEntity httpEntity) {
            try {
                EntityUtils.consume(httpEntity);
            } catch (IOException ignore) {
                // ignored
            }
            /*try {
                ((BasicManagedEntity) httpEntity).abortConnection();
            } catch (IOException ignore) {
                // ignored
            }*/
        }


        private class MonitoredOutputStream extends OutputStream {
            private final OutputStream outputStream;

            public MonitoredOutputStream(OutputStream outputStream) {
                this.outputStream = outputStream;
            }

            @Override
            public void close() throws IOException {
                outputStream.close();
            }

            @Override
            public void flush() throws IOException {
                outputStream.flush();
            }

            @Override
            public void write(byte[] b) throws IOException {
                outputStream.write(b);
                track.incDownloadedBytes(b.length);
                fireDownloadBytesChanged();
            }

            @Override
            public void write(byte[] b, int off, int len) throws IOException {
                outputStream.write(b, off, len);
                track.incDownloadedBytes(len);
                fireDownloadBytesChanged();
            }

            @Override
            public void write(int b) throws IOException {
                outputStream.write(b);
                track.incDownloadedBytes(1);
                fireDownloadBytesChanged();
            }
        }
    }
}
TOP

Related Classes of com.groovesquid.service.DownloadService$DownloadTask

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.