public static Task createDownloadTask( ApiSession sess, String servicename, Path local, CommonPath remote, Struct storeParams, boolean allowResume) { DownloadFile work = new DownloadFile(); work.session = sess; RecordStruct params = new RecordStruct( new FieldStruct("LocalPath", local), new FieldStruct("RemotePath", remote), new FieldStruct("ServiceName", servicename), new FieldStruct("TransferParams", storeParams)); if (allowResume && Files.exists(local)) { try { params.setField("Offset", Files.size(local)); } catch (IOException x) { Logger.error("Unable to get file size for: " + local); return null; } } return new Task() .withTitle("Download file " + local) .withWork(work) .withSubContext() .withParams(params) .withTimeout(1) .withDeadline(0); }
public Drawable getDrawable() { if (downloadFile.exists()) { return AttachedImageDrawable.drawableFromPath(this, downloadFile.getFile().getAbsolutePath()); } AvatarData.asyncRequestDownload(userId); return getDefaultDrawable(); }
private void tableSelectionChanged() { if (selectedDownload != null) selectedDownload.deleteObserver(DownloadGUI.this); if (!clearing && table.getSelectedRow() > -1) { selectedDownload = tableModel.getDownload(table.getSelectedRow()); selectedDownload.addObserver(DownloadGUI.this); updateButtons(); } }
private synchronized void cleanup() { Iterator<DownloadFile> iterator = cleanupCandidates.iterator(); while (iterator.hasNext()) { DownloadFile downloadFile = iterator.next(); if (downloadFile != currentPlaying && downloadFile != currentDownloading) { if (downloadFile.cleanup()) { iterator.remove(); } } } }
public BufferTask(DownloadFile downloadFile, int position) { this.downloadFile = downloadFile; this.position = position; partialFile = downloadFile.getPartialFile(); // Calculate roughly how many bytes BUFFER_LENGTH_SECONDS corresponds to. int bitRate = downloadFile.getBitRate(); long byteCount = Math.max(100000, bitRate * 1024 / 8 * BUFFER_LENGTH_SECONDS); // Find out how large the file should grow before resuming playback. expectedFileSize = partialFile.length() + byteCount; }
@Override public synchronized void clearIncomplete() { reset(); Iterator<DownloadFile> iterator = downloadList.iterator(); while (iterator.hasNext()) { DownloadFile downloadFile = iterator.next(); if (!downloadFile.isCompleteFileAvailable()) { iterator.remove(); } } lifecycleSupport.serializeDownloadQueue(); updateJukeboxPlaylist(); }
@NonNull public Drawable getDrawable() { Drawable drawable = MyImageCache.getAvatarDrawable(this, downloadFile.getFilePath()); if (drawable == MyDrawableCache.BROKEN) { return getDefaultDrawable(); } else if (drawable != null) { return drawable; } if (!downloadFile.exists()) { AvatarData.asyncRequestDownload(userId); } return getDefaultDrawable(); }
@Override public synchronized DownloadFile forSong(MusicDirectory.Entry song) { for (DownloadFile downloadFile : downloadList) { if (downloadFile.getSong().equals(song)) { return downloadFile; } } DownloadFile downloadFile = downloadFileCache.get(song); if (downloadFile == null) { downloadFile = new DownloadFile(this, song); downloadFileCache.put(song, downloadFile); } return downloadFile; }
@Override public synchronized void download( List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext) { shufflePlay = false; int offset = 1; if (songs.isEmpty()) { return; } if (save) { for (MusicDirectory.Entry song : songs) { DownloadFile downloadFile = forSong(song); downloadFile.pin(); if (!downloadFile.isWorkDone() && !downloadList.contains(downloadFile)) { downloadList.add(downloadFile); } } } else if (playNext) { if (autoplay && getCurrentPlayingIndex() >= 0) { offset = 0; } for (MusicDirectory.Entry song : songs) { DownloadFile downloadFile = new DownloadFile(this, song); downloadList.add(getCurrentPlayingIndex() + offset, downloadFile); offset++; } } else { for (MusicDirectory.Entry song : songs) { DownloadFile downloadFile = new DownloadFile(this, song); downloadList.add(downloadFile); } } revision++; updateJukeboxPlaylist(); if (autoplay) { play(0); } else { if (currentPlaying == null) { currentPlaying = downloadList.get(0); } checkDownloads(); } lifecycleSupport.serializeDownloadQueue(); }
synchronized void setCurrentPlaying(DownloadFile currentPlaying) { this.currentPlaying = currentPlaying; MusicDirectory.Entry song = currentPlaying != null ? currentPlaying.getSong() : null; Util.broadcastNewTrackInfo(this, song); NotificationUtil.updateNotification(this, this, handler, song, song != null); }
public void serializeDownloadQueue() { State state = new State(); for (DownloadFile downloadFile : downloadService.getDownloads()) { state.songs.add(downloadFile.getSong()); } state.currentPlayingIndex = downloadService.getCurrentPlayingIndex(); state.currentPlayingPosition = downloadService.getPlayerPosition(); Log.i( TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition); FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER); }
public void restore( List<MusicDirectory.Entry> songs, int currentPlayingIndex, int currentPlayingPosition) { download(songs, false, false, false); if (currentPlayingIndex != -1) { play(currentPlayingIndex, false); if (currentPlaying.isCompleteFileAvailable()) { doPlay(currentPlaying, currentPlayingPosition, false); } } }
/** * Update the progress bar of the currently downloaded file in main window. Only update if progess * has at least increased by one percent of the total file size of the downloaded file. * * @param downloadedBytes The current amount of downloaded bytes * @param lastProgBarUpdate The byte count at the last progress bar update * @param file The download file * @return The byte count at the last progress bar update */ private int updateProgressBar(int downloadedBytes, int lastProgBarUpdate, DownloadFile file) { int totalSize = (int) file.getTotalFileSize(); // only update progess bar if progess has at least increased by one percent int diff = downloadedBytes - lastProgBarUpdate; int onePercent = (int) totalSize / 100; if (diff >= onePercent) { final String filename = file.getFilename(); final int db = downloadedBytes; SwingUtilities.invokeLater( new Runnable() { public void run() { mainApp.updateDownloadQueue(filename, db); } }); return downloadedBytes; // prog bar updated, so return the new byte count } return lastProgBarUpdate; // no update, so return the previous byte count }
@Override public void setJukeboxEnabled(boolean jukeboxEnabled) { this.jukeboxEnabled = jukeboxEnabled; jukeboxService.setEnabled(jukeboxEnabled); if (jukeboxEnabled) { reset(); // Cancel current download, if necessary. if (currentDownloading != null) { currentDownloading.cancelDownload(); } } }
public synchronized void clear(boolean serialize) { reset(); downloadList.clear(); revision++; if (currentDownloading != null) { currentDownloading.cancelDownload(); currentDownloading = null; } setCurrentPlaying(null); if (serialize) { lifecycleSupport.serializeDownloadQueue(); } updateJukeboxPlaylist(); }
@Override public synchronized void remove(DownloadFile downloadFile) { if (downloadFile == currentDownloading) { currentDownloading.cancelDownload(); currentDownloading = null; } if (downloadFile == currentPlaying) { reset(); setCurrentPlaying(null); } downloadList.remove(downloadFile); revision++; lifecycleSupport.serializeDownloadQueue(); updateJukeboxPlaylist(); }
private boolean bufferComplete() { boolean completeFileAvailable = downloadFile.isCompleteFileAvailable(); long size = partialFile.length(); LOG.info( "Buffering " + partialFile + " (" + size + "/" + expectedFileSize + ", " + completeFileAvailable + ")"); return completeFileAvailable || size >= expectedFileSize; }
/** * Download .zip file specified by url, then unzip it to a folder in external storage. * * @param url */ private void downloadAllAssets(String url) { // File zipDir = ExternalStorage.get // Temp folder for holding asset during download File zipDir = ExternalStorage.getSDCacheDir(this, "tmp"); // File path to store .zip file before unzipping File zipFile = new File(zipDir.getPath() + "/temp.zip"); // Folder to hold unzipped output File outputDir = ExternalStorage.getSDCacheDir(this, "unzipped"); try { DownloadFile.download(url, zipFile, zipDir); unzipFile(zipFile, outputDir); } finally { zipFile.delete(); } }
@Override public synchronized int getPlayerDuration() { if (currentPlaying != null) { Integer duration = currentPlaying.getSong().getDuration(); if (duration != null) { return duration * 1000; } } if (playerState != IDLE && playerState != DOWNLOADING && playerState != PlayerState.PREPARING) { try { return mediaPlayer.getDuration(); } catch (Exception x) { handleError(x); } } return 0; }
synchronized void setPlayerState(PlayerState playerState) { LOG.info(this.playerState.name() + " -> " + playerState.name() + " (" + currentPlaying + ")"); if (playerState == PAUSED) { lifecycleSupport.serializeDownloadQueue(); } Util.broadcastPlaybackStatusChange(this, playerState); this.playerState = playerState; if (playerState == STARTED) { scrobbler.scrobble(this, currentPlaying, false); NotificationUtil.setNotificationHiddenByUser(this, false); } else if (playerState == COMPLETED) { scrobbler.scrobble(this, currentPlaying, true); } MusicDirectory.Entry song = currentPlaying == null ? null : currentPlaying.getSong(); NotificationUtil.updateNotification(this, this, handler, song, this.playerState == STARTED); }
private void updateButtons() { if (selectedDownload != null) { int status = selectedDownload.getStatus(); switch (status) { case DownloadFile.DOWNLOADING: pauseButton.setEnabled(true); resumeButton.setEnabled(false); cancelButton.setEnabled(true); clearButton.setEnabled(false); break; case DownloadFile.PAUSED: pauseButton.setEnabled(false); resumeButton.setEnabled(true); cancelButton.setEnabled(true); clearButton.setEnabled(false); break; case DownloadFile.ERROR: pauseButton.setEnabled(false); resumeButton.setEnabled(true); cancelButton.setEnabled(false); clearButton.setEnabled(true); break; default: pauseButton.setEnabled(false); resumeButton.setEnabled(false); cancelButton.setEnabled(false); clearButton.setEnabled(true); } } else { pauseButton.setEnabled(false); resumeButton.setEnabled(false); cancelButton.setEnabled(false); clearButton.setEnabled(false); } }
/** * This method is called when a whole download file has been finished downloading. It updates main * application window and starts the decoding thread. * * @param dlFile The DownloadFile object that is finished */ private void handleFinishedDlFile(final DownloadFile dlFile) { final String filename = dlFile.getFilename(); logger.msg("File downloading finished: " + filename, MyLogger.SEV_INFO); // notify application that download has finished SwingUtilities.invokeLater( new Runnable() { public void run() { mainApp.fileDownloadFinished(filename); mainApp.setProgBarToDecoding(filename, dlFile.getSegCount()); } }); // create result vector Vector<byte[]> articleData = new Vector<byte[]>(); Vector<RspHandler> rspHandlers = dlFileRspHandlerMap.get(dlFile); for (int i = 0; i < rspHandlers.size(); i++) { byte[] tmpArray = removeFirstLine(rspHandlers.get(i).getData(true)); articleData.add(tmpArray); rspHandlers.set(i, null); // free some memory } // call garbage collector rspHandlers = null; dlFileRspHandlerMap.remove(dlFile); Runtime.getRuntime().gc(); logger.msg( "First line(s) dump:\n" + HelloNzbToolkit.firstLineFromByteData(articleData.get(0), 2), MyLogger.SEV_DEBUG); // determine data encoding (yenc or UU) String encoding = null; boolean bHasData = false; for (int i = 0; i < articleData.size(); i++) { byte[] abyteHelp = articleData.get(i); if (abyteHelp.length > 0) { bHasData = true; if (bytesEqualsString(abyteHelp, "=ybegin")) { encoding = "yenc"; break; } else if (bytesEqualsString(abyteHelp, "begin ")) { encoding = "uu"; break; } } } if (encoding == null) { if (bHasData) { encoding = "yenc"; logger.msg( "No suitable decoder (no data) found for downloaded file: " + dlFile.getFilename() + " -- Assuming yenc.", MyLogger.SEV_WARNING); } else { // too bad, no decoder found for this file :( logger.msg( "No suitable decoder found for downloaded file (no data): " + dlFile.getFilename(), MyLogger.SEV_ERROR); // update main application window SwingUtilities.invokeLater( new Runnable() { public void run() { mainApp.fileDecodingFinished(dlFile.getFilename()); } }); return; } } /* * // determine data encoding String encoding = null; * if(bytesEqualsString(articleData.get(0), "=ybegin")) encoding = * "yenc"; else if(bytesEqualsString(articleData.get(0), "begin ")) * encoding = "uu"; else { // too bad, no decoder found for this file :( * logger.msg("No suitable decoder found for downloaded file: " + * dlFile.getFilename(), MyLogger.SEV_ERROR); * * // update main application window SwingUtilities.invokeLater(new * Runnable() { public void run() { * mainApp.fileDecodingFinished(dlFile.getFilename()); } } ); * * return; } */ // start data decoding background thread FileDecoder fileDecoder = new FileDecoder(mainApp, dlDir, dlFile, articleData, encoding); Thread t = new Thread(fileDecoder); t.start(); }
/** This method starts the thread and begins to download the file. */ public void run() { int maxThreads = Integer.parseInt(mainApp.getPrefValue("ServerSettingsThreadCount")); int runningThreads = 0; HashMap<String, Integer> downloadedBytes = new HashMap<String, Integer>(); HashMap<String, Integer> lastProgBarUpdate = new HashMap<String, Integer>(); // loop at all segments of the download file while (!shutdown && (segQueue.hasMoreSegments() || runningThreads > 0)) { // more segments to go? while (segQueue.hasMoreSegments() && runningThreads < maxThreads && !pause && nioClient.hasFreeSlot()) { // get next download segment of the download file DownloadFileSegment seg = segQueue.nextSegment(); if (seg == null) break; String filename = seg.getDlFile().getFilename(); logger.msg("Downloading next segment of file: " + filename, MyLogger.SEV_DEBUG); // create new response handler RspHandler newHandler = new RspHandler(seg); activeRspHandlers.add(newHandler); // map the new response handler to the download file Vector<RspHandler> tmpVector = dlFileRspHandlerMap.get(seg.getDlFile()); if (tmpVector == null) tmpVector = new Vector<RspHandler>(); tmpVector.add(newHandler); dlFileRspHandlerMap.put(seg.getDlFile(), tmpVector); // start data download nioClient.fetchArticleData(seg.getGroups().firstElement(), seg.getArticleId(), newHandler); // increase thread counter runningThreads++; } // check if the next element of the result set is already finished Vector<RspHandler> toRemoveVector = new Vector<RspHandler>(); for (int i = 0; i < activeRspHandlers.size(); i++) { RspHandler handler = activeRspHandlers.get(i); // handle error response from NNTP server if (handler.getError() == RspHandler.ERR_NONE) { // no error, do nothing } else if (handler.getError() == RspHandler.ERR_AUTH) { // do nothing for this error (?) } else if (handler.getError() == RspHandler.ERR_FETCH) { // TODO: handle "430 no such article" error (?) String msg = "no such article found: <" + handler.dlFileSeg().getArticleId() + "> (" + handler.getErrorMsg() + ")"; logger.msg(msg, MyLogger.SEV_WARNING); } else { // all other errors shutdown = true; } // update downloaded byte counter ... DownloadFile dlFile = handler.dlFileSeg().getDlFile(); String filename = dlFile.getFilename(); int bytes = 0; Integer bytesInt = downloadedBytes.get(filename); if (bytesInt != null) bytes = bytesInt; bytes += handler.newByteCount(); downloadedBytes.put(filename, bytes); // ... and progres bar in main window int last = 0; Integer lastInt = lastProgBarUpdate.get(filename); if (lastInt != null) last = lastInt; last = updateProgressBar(bytes, last, dlFile); lastProgBarUpdate.put(filename, last); // all data downloaded? if (handler.isFinished()) { toRemoveVector.add(handler); runningThreads--; decrSegCount(filename); // decrease main window segment // counter // segment done, so check if whole download file is finished // now dlFile.removeSegment(handler.dlFileSeg().getIndex()); if (!dlFile.hasMoreSegments()) { try { handleFinishedDlFile(dlFile); } catch (Exception e) { logger.printStackTrace(e); } } } } activeRspHandlers.removeAll(toRemoveVector); toRemoveVector.removeAllElements(); // all tasks done? if (!segQueue.hasMoreSegments() && runningThreads == 0) { break; } try { // let the thread sleep a bit Thread.sleep(10); } catch (InterruptedException e) { // shutdown if interrupted shutdown = true; } } // end of main loop logger.msg("FileDownloader has finished downloading all files", MyLogger.SEV_DEBUG); }
public void displaySongInfo(final MusicDirectory.Entry song) { Integer bitrate = null; String format = null; long size = 0; try { DownloadFile downloadFile = new DownloadFile(SubsonicTabActivity.this, song, false); File file = downloadFile.getCompleteFile(); if (file.exists()) { MediaMetadataRetriever metadata = new MediaMetadataRetriever(); metadata.setDataSource(file.getAbsolutePath()); String tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE); bitrate = Integer.parseInt((tmp != null) ? tmp : "0") / 1000; format = FileUtil.getExtension(file.getName()); size = file.length(); if (Util.isOffline(SubsonicTabActivity.this)) { song.setGenre(metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE)); String year = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR); song.setYear(Integer.parseInt((year != null) ? year : "0")); } } } catch (Exception e) { Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver"); } String msg = ""; if (!song.isVideo()) { msg += "Artist: " + song.getArtist() + "\nAlbum: " + song.getAlbum(); } if (song.getTrack() != null && song.getTrack() != 0) { msg += "\nTrack: " + song.getTrack(); } if (song.getGenre() != null && !"".equals(song.getGenre())) { msg += "\nGenre: " + song.getGenre(); } if (song.getYear() != null && song.getYear() != 0) { msg += "\nYear: " + song.getYear(); } if (!Util.isOffline(SubsonicTabActivity.this)) { msg += "\nServer Format: " + song.getSuffix(); if (song.getBitRate() != null && song.getBitRate() != 0) { msg += "\nServer Bitrate: " + song.getBitRate() + " kpbs"; } } if (format != null && !"".equals(format)) { msg += "\nCached Format: " + format; } if (bitrate != null && bitrate != 0) { msg += "\nCached Bitrate: " + bitrate + " kpbs"; } if (size != 0) { msg += "\nSize: " + Util.formatBytes(size); } if (song.getDuration() != null && song.getDuration() != 0) { msg += "\nLength: " + Util.formatDuration(song.getDuration()); } new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle(song.getTitle()) .setMessage(msg) .show(); }
private void actionPause() { selectedDownload.pause(); updateButtons(); }
private void actionResume() { selectedDownload.resume(); updateButtons(); }
private void actionCancel() { selectedDownload.cancel(); updateButtons(); }
protected synchronized void checkDownloads() { if (!Util.isExternalStoragePresent() || !lifecycleSupport.isExternalStorageAvailable()) { return; } if (shufflePlay) { checkShufflePlay(); } if (jukeboxEnabled || !Util.isNetworkConnected(this)) { return; } if (downloadList.isEmpty()) { return; } // Need to download current playing? if (currentPlaying != null && currentPlaying != currentDownloading && !currentPlaying.isCompleteFileAvailable()) { // Cancel current download, if necessary. if (currentDownloading != null) { currentDownloading.cancelDownload(); } currentDownloading = currentPlaying; currentDownloading.download(); cleanupCandidates.add(currentDownloading); } // Find a suitable target for download. else if (currentDownloading == null || currentDownloading.isWorkDone() || currentDownloading.isFailed()) { int n = size(); if (n == 0) { return; } int preloaded = 0; int start = currentPlaying == null ? 0 : getCurrentPlayingIndex(); int i = start; do { DownloadFile downloadFile = downloadList.get(i); if (!downloadFile.isWorkDone()) { if (downloadFile.shouldSave() || preloaded < Util.getPreloadCount(this)) { currentDownloading = downloadFile; currentDownloading.download(); cleanupCandidates.add(currentDownloading); break; } } else if (currentPlaying != downloadFile) { preloaded++; } i = (i + 1) % n; } while (i != start); } // Delete obsolete .partial and .complete files. cleanup(); }
private synchronized void doPlay(final DownloadFile downloadFile, int position, boolean start) { try { final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); downloadFile.updateModificationDate(); mediaPlayer.setOnCompletionListener(null); mediaPlayer.reset(); setPlayerState(IDLE); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setDataSource(file.getPath()); setPlayerState(PREPARING); mediaPlayer.prepare(); setPlayerState(PREPARED); mediaPlayer.setOnCompletionListener( new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mediaPlayer) { // Acquire a temporary wakelock, since when we return from // this callback the MediaPlayer will release its wakelock // and allow the device to go to sleep. wakeLock.acquire(60000); setPlayerState(COMPLETED); // If COMPLETED and not playing partial file, we are *really" finished // with the song and can move on to the next. if (!file.equals(downloadFile.getPartialFile())) { onSongCompleted(); return; } // If file is not completely downloaded, restart the playback from the current // position. int pos = mediaPlayer.getCurrentPosition(); synchronized (DownloadServiceImpl.this) { // Work-around for apparent bug on certain phones: If close (less than ten seconds) // to the end // of the song, skip to the next rather than restarting it. Integer duration = downloadFile.getSong().getDuration() == null ? null : downloadFile.getSong().getDuration() * 1000; if (duration != null) { if (Math.abs(duration - pos) < 10000) { LOG.info("Skipping restart from " + pos + " of " + duration); onSongCompleted(); return; } } LOG.info("Requesting restart from " + pos + " of " + duration); reset(); bufferTask = new BufferTask(downloadFile, pos); bufferTask.start(); } } }); if (position != 0) { LOG.info("Restarting player from position " + position); mediaPlayer.seekTo(position); } if (start) { mediaPlayer.start(); setPlayerState(STARTED); } else { setPlayerState(PAUSED); } lifecycleSupport.serializeDownloadQueue(); } catch (Exception x) { handleError(x); } }
public void update(Observable o, Object arg) { if (selectedDownload != null && selectedDownload.equals(o)) updateButtons(); }