/**
* MediaSniper 3.0 (2008-08-02)
* Copyright 2007 - 2008 Zach Scrivena
* zachscrivena@gmail.com
* http://mediasniper.sourceforge.net/
*
* Simple program for downloading media files from popular websites.
*
* TERMS AND CONDITIONS:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.freeshell.zs.mediasniper;
import java.io.File;
import java.net.URL;
import java.util.Calendar;
import org.freeshell.zs.common.Debug;
import org.freeshell.zs.common.Downloader;
import org.freeshell.zs.common.HtmlManipulator;
/**
* Represent a download.
*/
class Download
implements Runnable
{
/** refresh interval, in milliseconds */
private static final long REFRESH_INTERVAL_MILLISECONDS = 100L;
/** parent MediaSniper object */
private final MediaSniper parent;
/** title of this download */
private final String title;
/** URL of the remote resource to be downloaded */
private final URL url;
/** string representation of the field <code>url</code> */
private final String urlString;
/** local file to be populated (full canonical pathname) */
volatile private File file;
/** creation time of this download */
private final String time;
/** length of the remote resource, in number of bytes; -1 if unknown */
volatile private int length = -1;
/** string representation of the length of the remote resource; "unknown" if unknown" */
volatile private String lengthString = "unknown";
/** Downloader object corresponding to this download */
volatile private Downloader downloader = null;
/** is the download completed? */
volatile private boolean isCompleted = false;
/**
* Constructor.
*
* @param title
* title of this download
* @param url
* URL of the remote resource to be downloaded
* @param file
* local file to be populated
*/
Download(
final MediaSniper parent,
final String title,
final URL url,
final File file)
{
this.parent = parent;
this.title = title;
this.url = url;
this.urlString = url.toString();
this.file = file;
this.time = String.format("%1$tF %1$tT", Calendar.getInstance());
}
/**
* Get the title of this download.
*
* @return
* title of this download
*/
String getTitle()
{
return title;
}
/**
* Get the string representation of the URL of the remote resource to be downloaded.
*
* @return
* string representation of the URL
*/
String getUrlString()
{
return urlString;
}
/**
* Get the local file to be populated.
*
* @return
* local file to be populated
*/
File getFile()
{
return file;
}
/**
* Get the name of the local file to be populated.
* A relative pathname is returned if the local file is in the download directory;
* otherwise an absolute pathname is returned.
*
* @return
* name of local file
*/
String getFilename()
{
final String p = file.getPath();
String downloadDirectory = parent.properties.getFile("download.directory").getPath();
if (!downloadDirectory.endsWith(File.separator))
{
downloadDirectory += File.separator;
}
if (p.startsWith(downloadDirectory))
{
return p.substring(downloadDirectory.length());
}
else
{
return p;
}
}
/**
* Set the name of the local file to be populated.
*
* @param f
* name of local file
* @return
* true if the specified name is accepted; false otherwise
*/
boolean setFilename(
final String newFilename)
{
final File newFile = parent.localFilenameManager.replaceFilename(
file,
parent.properties.getFile("download.directory"),
newFilename);
if (newFile == null)
{
/* user-specified new filename is NOT accepted */
return false;
}
else
{
/* update local filename */
file = newFile;
return true;
}
}
/**
* Get the length of this download, in number of bytes.
*
* @return
* length of this download; -1 if unknown
*/
int getLength()
{
if (length == -1)
{
if (downloader == null)
{
length = -1;
}
else
{
length = downloader.getLength();
}
}
return length;
}
/**
* Get a string representation of the length of this download.
*
* @return
* string representation of the length of this download; "unknown" if unknown
*/
String getLengthString()
{
if ("unknown".equals(lengthString))
{
final int len = getLength();
if (len < 0)
{
lengthString = "unknown";
}
else if (len < 1024)
{
lengthString = String.format("%d b", len);
}
else if (len < 1048576)
{
lengthString = String.format("%.1f kb", len / 1024.0);
}
else if (len < 1073741824)
{
lengthString = String.format("%.1f Mb", len / 1048576.0);
}
else
{
lengthString = String.format("%.1f Gb", len / 1073741824.0);
}
}
return lengthString;
}
/**
* Get a string describing the current progress.
*
* @return
* string describing the current progress
*/
String getProgressString()
{
if (downloader == null)
{
return "Waiting to start";
}
else
{
return downloader.getProgressString();
}
}
/**
* Get the percentage describing the current progress.
*
* @return
* percentage describing the current progress; -1 if unknown
*/
int getProgressPercent()
{
if (downloader == null)
{
return -1;
}
else
{
return downloader.getProgressPercent();
}
}
/**
* Is the download completed?
*
* @return
* true if this download is completed; false otherwise
*/
boolean isCompleted()
{
return isCompleted;
}
/**
* Get the tooltip text for this download.
*
* @return
* tooltip text for this download
*/
String getToolTipText()
{
return "<html>Title: <b>" + title + "</b><br />" +
"URL: " + HtmlManipulator.quoteHtml(urlString) + "<br />" +
"Size: " + getLengthString() + "<br />" +
"Local filename: <b>" + HtmlManipulator.quoteHtml(getFilename()) + "</b><br />" +
"Time added: " + time + "</html>";
}
/**
* Start downloading the remote resource to the local file.
* This method should run on a dedicated worker thread, not the EDT.
*/
public void run()
{
downloader = new Downloader(url, file);
new Thread(downloader).start();
while (true)
{
if (downloader.isProgressUpdated())
{
parent.refreshDownloadOnTable(this);
}
if (downloader.isCompleted())
{
try
{
downloader.waitUntilCompleted();
}
catch (Exception e)
{
/* ignore */
}
parent.refreshDownloadOnTable(this);
isCompleted = true;
return;
}
Debug.sleep(REFRESH_INTERVAL_MILLISECONDS);
}
}
}