Browse Source

Separated the seeders and leechers (peers), which means getting these fields for all the support torrent clients. Fixes #25.

pull/148/merge
Eric Kok 10 years ago
parent
commit
f8fd600785
  1. 6
      core/res/layout/fragment_details_header.xml
  2. 3
      core/res/values/strings.xml
  3. 4
      core/src/org/transdroid/core/gui/lists/LocalTorrent.java
  4. 9
      core/src/org/transdroid/core/gui/lists/TorrentDetailsView.java
  5. 10
      lib/src/org/transdroid/daemon/BitComet/BitCometAdapter.java
  6. 141
      lib/src/org/transdroid/daemon/Bitflu/BitfluAdapter.java
  7. 115
      lib/src/org/transdroid/daemon/BuffaloNas/BuffaloNasAdapter.java
  8. 10
      lib/src/org/transdroid/daemon/DLinkRouterBT/DLinkRouterBTAdapter.java
  9. 20
      lib/src/org/transdroid/daemon/Deluge/DelugeAdapter.java
  10. 6
      lib/src/org/transdroid/daemon/Ktorrent/StatsParser.java
  11. 49
      lib/src/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java
  12. 303
      lib/src/org/transdroid/daemon/Rtorrent/RtorrentAdapter.java
  13. 13
      lib/src/org/transdroid/daemon/Synology/SynologyAdapter.java
  14. 211
      lib/src/org/transdroid/daemon/Torrent.java
  15. 3
      lib/src/org/transdroid/daemon/Transmission/TransmissionAdapter.java
  16. 4
      lib/src/org/transdroid/daemon/Utorrent/UtorrentAdapter.java
  17. 8
      lib/src/org/transdroid/daemon/Vuze/VuzeAdapter.java

6
core/res/layout/fragment_details_header.xml

@ -99,7 +99,7 @@
android:textSize="@dimen/text_enlargednumbers" /> android:textSize="@dimen/text_enlargednumbers" />
<TextView <TextView
android:id="@+id/seeders_text" android:id="@+id/leechers_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/upspeed_text" android:layout_below="@id/upspeed_text"
@ -154,10 +154,10 @@
android:textSize="@dimen/text_enlargednumbers" /> android:textSize="@dimen/text_enlargednumbers" />
<TextView <TextView
android:id="@+id/leechers_text" android:id="@+id/seeders_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignBaseline="@id/seeders_text" android:layout_alignBaseline="@id/leechers_text"
android:layout_marginRight="@dimen/margin_half" android:layout_marginRight="@dimen/margin_half"
android:layout_toLeftOf="@id/separator" android:layout_toLeftOf="@id/separator"
android:textIsSelectable="false" android:textIsSelectable="false"

3
core/res/values/strings.xml

@ -104,7 +104,8 @@
<string name="status_ofsize">OF %1$s</string> <string name="status_ofsize">OF %1$s</string>
<string name="status_unknowneta">UNKNOWN ETA</string> <string name="status_unknowneta">UNKNOWN ETA</string>
<string name="status_ratio">RATIO %1$s</string> <string name="status_ratio">RATIO %1$s</string>
<string name="status_peers">%1$s OF %2$s PEERS</string> <string name="status_seeders">%1$s OF %2$s SEEDERS</string>
<string name="status_leechers">%1$s OF %2$s LEECHERS</string>
<string name="status_speed_up" translatable="false">↑ %1$s</string> <string name="status_speed_up" translatable="false">↑ %1$s</string>
<string name="status_speed_down" translatable="false">↓ %1$s</string> <string name="status_speed_down" translatable="false">↓ %1$s</string>
<string name="status_speed_down_details" translatable="false">%1$s ↓</string> <string name="status_speed_down_details" translatable="false">%1$s ↓</string>

4
core/src/org/transdroid/core/gui/lists/LocalTorrent.java

@ -143,9 +143,9 @@ public class LocalTorrent {
case Checking: case Checking:
return r.getString(R.string.status_checking); return r.getString(R.string.status_checking);
case Downloading: case Downloading:
return r.getString(R.string.status_peers, t.getPeersSendingToUs(), t.getPeersConnected()); return r.getString(R.string.status_leechers, t.getSeedersConnected(), t.getSeedersKnown());
case Seeding: case Seeding:
return r.getString(R.string.status_peers, t.getPeersGettingFromUs(), t.getPeersConnected()); return r.getString(R.string.status_seeders, t.getLeechersConnected(), t.getLeechersKnown());
case Paused: case Paused:
return r.getString(R.string.status_paused); return r.getString(R.string.status_paused);
case Queued: case Queued:

9
core/src/org/transdroid/core/gui/lists/TorrentDetailsView.java

@ -85,11 +85,10 @@ public class TorrentDetailsView extends RelativeLayout {
statusLayout.setStatus(torrent.getStatusCode()); statusLayout.setStatus(torrent.getStatusCode());
statusText.setText(getResources().getString(R.string.status_status, local.getProgressStatusEta(getResources()))); statusText.setText(getResources().getString(R.string.status_status, local.getProgressStatusEta(getResources())));
ratioText.setText(getResources().getString(R.string.status_ratio, local.getRatioString())); ratioText.setText(getResources().getString(R.string.status_ratio, local.getRatioString()));
// TODO: Implement separate numbers of seeders and leechers seedersText.setText(getResources().getString(R.string.status_seeders, torrent.getSeedersConnected(),
seedersText.setText(getResources().getString(R.string.status_peers, torrent.getPeersSendingToUs(), torrent.getSeedersKnown()));
torrent.getPeersConnected())); leechersText.setText(getResources().getString(R.string.status_leechers, torrent.getLeechersConnected(),
leechersText.setText(getResources().getString(R.string.status_peers, torrent.getPeersSendingToUs(), torrent.getLeechersKnown()));
torrent.getPeersConnected()));
// TODO: Add field that displays torrent errors (as opposed to tracker errors) // TODO: Add field that displays torrent errors (as opposed to tracker errors)
// TODO: Add field that displays availability // TODO: Add field that displays availability

10
lib/src/org/transdroid/daemon/BitComet/BitCometAdapter.java

@ -467,10 +467,10 @@ public class BitCometAdapter implements IDaemonAdapter {
null, null,
rateDown, rateDown,
rateUp, rateUp,
leechers,
seeders, seeders,
knownLeechers,
knownSeeders, knownSeeders,
leechers,
knownLeechers,
(rateDown == 0? -1: (int) ((size - sizeDone) / rateDown)), (rateDown == 0? -1: (int) ((size - sizeDone) / rateDown)),
sizeDone, sizeDone,
sizeUp, sizeUp,
@ -545,10 +545,10 @@ public class BitCometAdapter implements IDaemonAdapter {
null, null,
rateDown, rateDown,
rateUp, rateUp,
leechers,
seeders, seeders,
seeders + leechers, seedersTotal,
seedersTotal + leechersTotal, leechers,
leechersTotal,
(int) ((status == TorrentStatus.Downloading && rateDown != 0)? (totalSize - sizeDone) / rateDown: -1), // eta (in seconds) = (total_size_in_btes - bytes_already_downloaded) / bytes_per_second (int) ((status == TorrentStatus.Downloading && rateDown != 0)? (totalSize - sizeDone) / rateDown: -1), // eta (in seconds) = (total_size_in_btes - bytes_already_downloaded) / bytes_per_second
sizeDone, sizeDone,
sizeUp, sizeUp,

141
lib/src/org/transdroid/daemon/Bitflu/BitfluAdapter.java

@ -15,7 +15,7 @@
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package org.transdroid.daemon.Bitflu; package org.transdroid.daemon.Bitflu;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -53,30 +53,27 @@ import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import org.transdroid.daemon.util.HttpHelper; import org.transdroid.daemon.util.HttpHelper;
import org.transdroid.daemon.util.DLog; import org.transdroid.daemon.util.DLog;
/** /**
* An adapter that allows for easy access to uTorrent torrent data. Communication * An adapter that allows for easy access to uTorrent torrent data. Communication is handled via authenticated JSON-RPC
* is handled via authenticated JSON-RPC HTTP GET requests and responses. * HTTP GET requests and responses.
*
* @author adrianulrich * @author adrianulrich
*
*/ */
// TODO: TransferRates support // TODO: TransferRates support
public class BitfluAdapter implements IDaemonAdapter { public class BitfluAdapter implements IDaemonAdapter {
private static final String LOG_NAME = "Bitflu daemon"; private static final String LOG_NAME = "Bitflu daemon";
private static final String JSON_ROOT = "Bitflu"; private static final String JSON_ROOT = "Bitflu";
private static final String RPC_TORRENT_LIST = "torrentList"; private static final String RPC_TORRENT_LIST = "torrentList";
private static final String RPC_PAUSE_TORRENT = "pause/"; private static final String RPC_PAUSE_TORRENT = "pause/";
private static final String RPC_RESUME_TORRENT = "resume/"; private static final String RPC_RESUME_TORRENT = "resume/";
private static final String RPC_CANCEL_TORRENT = "cancel/"; private static final String RPC_CANCEL_TORRENT = "cancel/";
private static final String RPC_REMOVE_TORRENT = "wipe/"; private static final String RPC_REMOVE_TORRENT = "wipe/";
private static final String RPC_TORRENT_FILES = "showfiles-ext/"; private static final String RPC_TORRENT_FILES = "showfiles-ext/";
private static final String RPC_START_DOWNLOAD = "startdownload/"; private static final String RPC_START_DOWNLOAD = "startdownload/";
private DaemonSettings settings; private DaemonSettings settings;
private DefaultHttpClient httpclient; private DefaultHttpClient httpclient;
/** /**
@ -88,13 +85,14 @@ public class BitfluAdapter implements IDaemonAdapter {
@Override @Override
public DaemonTaskResult executeTask(DaemonTask task) { public DaemonTaskResult executeTask(DaemonTask task) {
try { try {
switch (task.getMethod()) { switch (task.getMethod()) {
case Retrieve: case Retrieve:
// Request all torrents from server // Request all torrents from server
JSONObject result = makeBitfluRequest(RPC_TORRENT_LIST); JSONObject result = makeBitfluRequest(RPC_TORRENT_LIST);
return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonRetrieveTorrents(result.getJSONArray(JSON_ROOT)),null); return new RetrieveTaskSuccessResult((RetrieveTask) task,
parseJsonRetrieveTorrents(result.getJSONArray(JSON_ROOT)), null);
case GetStats: case GetStats:
return new GetStatsTaskSuccessResult((GetStatsTask) task, false, -1); return new GetStatsTaskSuccessResult((GetStatsTask) task, false, -1);
case Pause: case Pause:
@ -107,26 +105,28 @@ public class BitfluAdapter implements IDaemonAdapter {
// Remove a torrent // Remove a torrent
RemoveTask removeTask = (RemoveTask) task; RemoveTask removeTask = (RemoveTask) task;
String removeUriBase = RPC_CANCEL_TORRENT; String removeUriBase = RPC_CANCEL_TORRENT;
if(removeTask.includingData()) { if (removeTask.includingData()) {
removeUriBase = RPC_REMOVE_TORRENT; removeUriBase = RPC_REMOVE_TORRENT;
} }
DLog.d(LOG_NAME, "*** CALLING "+removeUriBase); DLog.d(LOG_NAME, "*** CALLING " + removeUriBase);
makeBitfluRequest(removeUriBase + task.getTargetTorrent().getUniqueID()); makeBitfluRequest(removeUriBase + task.getTargetTorrent().getUniqueID());
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case GetFileList: case GetFileList:
JSONObject jfiles = makeBitfluRequest(RPC_TORRENT_FILES + task.getTargetTorrent().getUniqueID()); JSONObject jfiles = makeBitfluRequest(RPC_TORRENT_FILES + task.getTargetTorrent().getUniqueID());
return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonShowFilesTorrent(jfiles.getJSONArray(JSON_ROOT))); return new GetFileListTaskSuccessResult((GetFileListTask) task,
parseJsonShowFilesTorrent(jfiles.getJSONArray(JSON_ROOT)));
case AddByUrl: case AddByUrl:
String url = URLEncoder.encode(((AddByUrlTask)task).getUrl(), "UTF-8"); String url = URLEncoder.encode(((AddByUrlTask) task).getUrl(), "UTF-8");
makeBitfluRequest(RPC_START_DOWNLOAD + url); makeBitfluRequest(RPC_START_DOWNLOAD + url);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case AddByMagnetUrl: case AddByMagnetUrl:
String magnet = URLEncoder.encode(((AddByMagnetUrlTask)task).getUrl(), "UTF-8"); String magnet = URLEncoder.encode(((AddByMagnetUrlTask) task).getUrl(), "UTF-8");
makeBitfluRequest(RPC_START_DOWNLOAD + magnet); makeBitfluRequest(RPC_START_DOWNLOAD + magnet);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
default: default:
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not supported by " + getType())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported,
task.getMethod() + " is not supported by " + getType()));
} }
} catch (JSONException e) { } catch (JSONException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString()));
@ -136,40 +136,41 @@ public class BitfluAdapter implements IDaemonAdapter {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, e.toString())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, e.toString()));
} }
} }
private JSONObject makeBitfluRequest(String addToUrl) throws DaemonException { private JSONObject makeBitfluRequest(String addToUrl) throws DaemonException {
try { try {
// Initialise the HTTP client // Initialise the HTTP client
if (httpclient == null) { if (httpclient == null) {
initialise(); initialise();
} }
//TLog.d(LOG_NAME, "Request to: "+ buildWebUIUrl() + addToUrl); // TLog.d(LOG_NAME, "Request to: "+ buildWebUIUrl() + addToUrl);
// Make request // Make request
HttpGet httpget = new HttpGet(buildWebUIUrl() + addToUrl); HttpGet httpget = new HttpGet(buildWebUIUrl() + addToUrl);
HttpResponse response = httpclient.execute(httpget); HttpResponse response = httpclient.execute(httpget);
// Read JSON response // Read JSON response
InputStream instream = response.getEntity().getContent(); InputStream instream = response.getEntity().getContent();
String result = HttpHelper.convertStreamToString(instream); String result = HttpHelper.convertStreamToString(instream);
int httpstatus = response.getStatusLine().getStatusCode(); int httpstatus = response.getStatusLine().getStatusCode();
if(httpstatus != 200) { if (httpstatus != 200) {
throw new DaemonException(ExceptionType.UnexpectedResponse, "Invalid reply from server, http status code: " + httpstatus); throw new DaemonException(ExceptionType.UnexpectedResponse,
"Invalid reply from server, http status code: " + httpstatus);
} }
if(result.equals("")) { // Empty responses are ok: add fake json content if (result.equals("")) { // Empty responses are ok: add fake json content
result = "empty_response"; result = "empty_response";
} }
JSONObject json = new JSONObject("{ \""+JSON_ROOT+"\" : "+ result +"}"); JSONObject json = new JSONObject("{ \"" + JSON_ROOT + "\" : " + result + "}");
instream.close(); instream.close();
return json; return json;
} catch (DaemonException e) { } catch (DaemonException e) {
throw e; throw e;
} catch (JSONException e) { } catch (JSONException e) {
@ -179,20 +180,21 @@ public class BitfluAdapter implements IDaemonAdapter {
DLog.d(LOG_NAME, "Error: " + e.toString()); DLog.d(LOG_NAME, "Error: " + e.toString());
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); throw new DaemonException(ExceptionType.ConnectionError, e.toString());
} }
} }
private ArrayList<Torrent> parseJsonRetrieveTorrents(JSONArray results) throws JSONException { private ArrayList<Torrent> parseJsonRetrieveTorrents(JSONArray results) throws JSONException {
ArrayList<Torrent> torrents = new ArrayList<Torrent>(); ArrayList<Torrent> torrents = new ArrayList<Torrent>();
if (results != null) { if (results != null) {
for (int i = 0; i < results.length(); i++) { for (int i = 0; i < results.length(); i++) {
JSONObject tor = results.getJSONObject(i); JSONObject tor = results.getJSONObject(i);
long done_bytes = tor.getLong("done_bytes"); long done_bytes = tor.getLong("done_bytes");
long total_bytes = tor.getLong("total_bytes"); long total_bytes = tor.getLong("total_bytes");
float percent = ((float)done_bytes/((float)total_bytes+1)); float percent = ((float) done_bytes / ((float) total_bytes + 1));
// @formatter:off
torrents.add(new Torrent(i, torrents.add(new Torrent(i,
tor.getString("key"), tor.getString("key"),
tor.getString("name"), tor.getString("name"),
@ -200,10 +202,10 @@ public class BitfluAdapter implements IDaemonAdapter {
"/" + settings.getOS().getPathSeperator(), "/" + settings.getOS().getPathSeperator(),
tor.getInt("speed_download"), tor.getInt("speed_download"),
tor.getInt("speed_upload"), tor.getInt("speed_upload"),
0, // 'uploading to' tor.getInt("active_clients"),
tor.getInt("active_clients"), tor.getInt("active_clients"), // Bitflu doesn't distinguish between seeders and leechers
tor.getInt("clients"),
tor.getInt("clients"), tor.getInt("clients"),
tor.getInt("clients"), // Bitflu doesn't distinguish between seeders and leechers
tor.getInt("eta"), tor.getInt("eta"),
done_bytes, done_bytes,
tor.getLong("uploaded_bytes"), tor.getLong("uploaded_bytes"),
@ -215,27 +217,28 @@ public class BitfluAdapter implements IDaemonAdapter {
null, // Not available null, // Not available
null, // Not available null, // Not available
settings.getType())); settings.getType()));
// @formatter:on
} }
} }
// Return the list // Return the list
return torrents; return torrents;
} }
private ArrayList<TorrentFile> parseJsonShowFilesTorrent(JSONArray response) throws JSONException { private ArrayList<TorrentFile> parseJsonShowFilesTorrent(JSONArray response) throws JSONException {
ArrayList<TorrentFile> files = new ArrayList<TorrentFile>(); ArrayList<TorrentFile> files = new ArrayList<TorrentFile>();
if(response != null) { if (response != null) {
for (int i = 0; i < response.length(); i++) { for (int i = 0; i < response.length(); i++) {
JSONObject finfo = response.getJSONObject(i); JSONObject finfo = response.getJSONObject(i);
long done_bytes = finfo.getLong("done") * finfo.getLong("chunksize"); long done_bytes = finfo.getLong("done") * finfo.getLong("chunksize");
long file_size = finfo.getLong("size"); long file_size = finfo.getLong("size");
if( done_bytes > file_size) { /* Shared chunk */ if (done_bytes > file_size) { /* Shared chunk */
done_bytes = file_size; done_bytes = file_size;
} }
// @formatter:off
files.add(new TorrentFile( files.add(new TorrentFile(
"" + i, "" + i,
finfo.getString("name"), finfo.getString("name"),
@ -245,19 +248,18 @@ public class BitfluAdapter implements IDaemonAdapter {
done_bytes, done_bytes,
Priority.Normal Priority.Normal
)); ));
// @formatter:on
} }
} }
return files; return files;
} }
private TorrentStatus convertBitfluStatus(JSONObject obj) throws JSONException { private TorrentStatus convertBitfluStatus(JSONObject obj) throws JSONException {
if( obj.getInt("paused") != 0 ) { if (obj.getInt("paused") != 0) {
return TorrentStatus.Paused; return TorrentStatus.Paused;
} } else if (obj.getLong("done_bytes") == obj.getLong("total_bytes")) {
else if (obj.getLong("done_bytes") == obj.getLong("total_bytes")) {
return TorrentStatus.Seeding; return TorrentStatus.Seeding;
} }
return TorrentStatus.Downloading; return TorrentStatus.Downloading;
@ -272,7 +274,7 @@ public class BitfluAdapter implements IDaemonAdapter {
httpclient = HttpHelper.createStandardHttpClient(settings, true); httpclient = HttpHelper.createStandardHttpClient(settings, true);
} }
/** /**
* Build the URL of the Transmission web UI from the user settings. * Build the URL of the Transmission web UI from the user settings.
* @return The URL of the RPC API * @return The URL of the RPC API
@ -281,7 +283,8 @@ public class BitfluAdapter implements IDaemonAdapter {
String webuiroot = ""; String webuiroot = "";
if (settings.getFolder() != null) if (settings.getFolder() != null)
webuiroot = settings.getFolder(); webuiroot = settings.getFolder();
return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + webuiroot + "/"; return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort()
+ webuiroot + "/";
} }
@Override @Override
@ -293,5 +296,5 @@ public class BitfluAdapter implements IDaemonAdapter {
public DaemonSettings getSettings() { public DaemonSettings getSettings() {
return this.settings; return this.settings;
} }
} }

115
lib/src/org/transdroid/daemon/BuffaloNas/BuffaloNasAdapter.java

@ -64,9 +64,7 @@ import com.android.internalcopy.http.multipart.Part;
/** /**
* The daemon adapter for the Buffalo NAS' integrated torrent client. * The daemon adapter for the Buffalo NAS' integrated torrent client.
*
* @author erickok * @author erickok
*
*/ */
public class BuffaloNasAdapter implements IDaemonAdapter { public class BuffaloNasAdapter implements IDaemonAdapter {
@ -74,74 +72,92 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
private DaemonSettings settings; private DaemonSettings settings;
private DefaultHttpClient httpclient; private DefaultHttpClient httpclient;
public BuffaloNasAdapter(DaemonSettings settings) { public BuffaloNasAdapter(DaemonSettings settings) {
this.settings = settings; this.settings = settings;
} }
@Override @Override
public DaemonTaskResult executeTask(DaemonTask task) { public DaemonTaskResult executeTask(DaemonTask task) {
try { try {
switch (task.getMethod()) { switch (task.getMethod()) {
case Retrieve: case Retrieve:
// Request all torrents from server // Request all torrents from server
JSONObject result = new JSONObject(makeRequest("/api/torrents-get")); JSONObject result = new JSONObject(makeRequest("/api/torrents-get"));
return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonTorrents(result),null); return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonTorrents(result), null);
case GetFileList: case GetFileList:
// Request files listing for a specific torrent // Request files listing for a specific torrent
String fhash = ((GetFileListTask)task).getTargetTorrent().getUniqueID(); String fhash = ((GetFileListTask) task).getTargetTorrent().getUniqueID();
JSONObject files = new JSONObject(makeRequest("/api/torrent-get-files", new BasicNameValuePair("hash", fhash))); JSONObject files = new JSONObject(makeRequest("/api/torrent-get-files", new BasicNameValuePair("hash",
fhash)));
return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonFiles(files, fhash)); return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonFiles(files, fhash));
case AddByFile: case AddByFile:
// Upload a local .torrent file // Upload a local .torrent file
String ufile = ((AddByFileTask)task).getFile(); String ufile = ((AddByFileTask) task).getFile();
makeUploadRequest("/api/torrent-add?start=yes", ufile); makeUploadRequest("/api/torrent-add?start=yes", ufile);
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case AddByUrl: case AddByUrl:
// Request to add a torrent by URL // Request to add a torrent by URL
String url = ((AddByUrlTask)task).getUrl(); String url = ((AddByUrlTask) task).getUrl();
makeRequest("/api/torrent-add", new BasicNameValuePair("url", url), new BasicNameValuePair("start", "yes")); // @formatter:off
makeRequest("/api/torrent-add",
new BasicNameValuePair("url", url),
new BasicNameValuePair("start", "yes"));
// @formatter:on
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Remove: case Remove:
// Remove a torrent // Remove a torrent
RemoveTask removeTask = (RemoveTask) task; RemoveTask removeTask = (RemoveTask) task;
makeRequest("/api/torrent-remove", new BasicNameValuePair("hash", removeTask.getTargetTorrent().getUniqueID()), // @formatter:off
new BasicNameValuePair("delete-torrent", "yes"), new BasicNameValuePair("delete-data", (removeTask.includingData()? "yes": "no"))); makeRequest("/api/torrent-remove",
new BasicNameValuePair("hash", removeTask.getTargetTorrent().getUniqueID()),
new BasicNameValuePair("delete-torrent", "yes"),
new BasicNameValuePair("delete-data", (removeTask.includingData() ? "yes" : "no")));
// @formatter:on
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Pause: case Pause:
// Pause a torrent // Pause a torrent
makeRequest("/api/torrent-stop", new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID())); makeRequest("/api/torrent-stop", new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID()));
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Resume: case Resume:
// Resume a torrent // Resume a torrent
makeRequest("/api/torrent-start", new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID())); makeRequest("/api/torrent-start", new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID()));
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case SetTransferRates: case SetTransferRates:
// Request to set the maximum transfer rates // Request to set the maximum transfer rates
SetTransferRatesTask ratesTask = (SetTransferRatesTask) task; SetTransferRatesTask ratesTask = (SetTransferRatesTask) task;
String dl = Integer.toString((ratesTask.getDownloadRate() == null? -1: ratesTask.getDownloadRate().intValue() * 1024)); String dl = Integer.toString((ratesTask.getDownloadRate() == null ? -1 : ratesTask.getDownloadRate()
String ul = Integer.toString((ratesTask.getUploadRate() == null? -1: ratesTask.getUploadRate().intValue() * 1024)); .intValue() * 1024));
makeRequest("/api/app-settings-set", new BasicNameValuePair("auto_bandwidth_management", "0"), new BasicNameValuePair("max_dl_rate", dl), new BasicNameValuePair("max_ul_rate", ul), new BasicNameValuePair("max_ul_rate_seed", ul)); String ul = Integer.toString((ratesTask.getUploadRate() == null ? -1 : ratesTask.getUploadRate()
.intValue() * 1024));
// @formatter:off
makeRequest("/api/app-settings-set",
new BasicNameValuePair("auto_bandwidth_management", "0"),
new BasicNameValuePair("max_dl_rate", dl),
new BasicNameValuePair("max_ul_rate", ul),
new BasicNameValuePair("max_ul_rate_seed", ul));
// @formatter:on
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
default: default:
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not supported by " + getType())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported,
task.getMethod() + " is not supported by " + getType()));
} }
} catch (JSONException e) { } catch (JSONException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString()));
@ -153,7 +169,7 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
private String makeRequest(String url, NameValuePair... params) throws DaemonException { private String makeRequest(String url, NameValuePair... params) throws DaemonException {
try { try {
// Initialise the HTTP client // Initialise the HTTP client
if (httpclient == null) { if (httpclient == null) {
initialise(HttpHelper.DEFAULT_CONNECTION_TIMEOUT); initialise(HttpHelper.DEFAULT_CONNECTION_TIMEOUT);
@ -175,12 +191,12 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl(url))); HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl(url)));
HttpEntity entity = response.getEntity(); HttpEntity entity = response.getEntity();
if (entity != null) { if (entity != null) {
// Read JSON response // Read JSON response
java.io.InputStream instream = entity.getContent(); java.io.InputStream instream = entity.getContent();
String result = HttpHelper.convertStreamToString(instream); String result = HttpHelper.convertStreamToString(instream);
instream.close(); instream.close();
// Return raw result // Return raw result
return result; return result;
} }
@ -194,7 +210,7 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
DLog.d(LOG_NAME, "Error: " + e.toString()); DLog.d(LOG_NAME, "Error: " + e.toString());
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); throw new DaemonException(ExceptionType.ConnectionError, e.toString());
} }
} }
private boolean makeUploadRequest(String path, String file) throws DaemonException { private boolean makeUploadRequest(String path, String file) throws DaemonException {
@ -211,20 +227,20 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
File upload = new File(URI.create(file)); File upload = new File(URI.create(file));
Part[] parts = { new FilePart("fileEl", upload) }; Part[] parts = { new FilePart("fileEl", upload) };
httppost.setEntity(new MultipartEntity(parts, httppost.getParams())); httppost.setEntity(new MultipartEntity(parts, httppost.getParams()));
// Make the request // Make the request
HttpResponse response = httpclient.execute(httppost); HttpResponse response = httpclient.execute(httppost);
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
throw new DaemonException(ExceptionType.FileAccessError, e.toString()); throw new DaemonException(ExceptionType.FileAccessError, e.toString());
} catch (Exception e) { } catch (Exception e) {
DLog.d(LOG_NAME, "Error: " + e.toString()); DLog.d(LOG_NAME, "Error: " + e.toString());
throw new DaemonException(ExceptionType.ConnectionError, e.toString()); throw new DaemonException(ExceptionType.ConnectionError, e.toString());
} }
} }
/** /**
* Instantiates an HTTP client with proper credentials that can be used for all Buffalo NAS requests. * Instantiates an HTTP client with proper credentials that can be used for all Buffalo NAS requests.
* @param connectionTimeout The connection timeout in milliseconds * @param connectionTimeout The connection timeout in milliseconds
@ -233,9 +249,9 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
private void initialise(int connectionTimeout) throws DaemonException { private void initialise(int connectionTimeout) throws DaemonException {
httpclient = HttpHelper.createStandardHttpClient(settings, true); httpclient = HttpHelper.createStandardHttpClient(settings, true);
} }
/** /**
* Build the URL of the http request from the user settings * Build the URL of the http request from the user settings
* @return The URL to request * @return The URL to request
@ -245,21 +261,23 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
} }
private ArrayList<Torrent> parseJsonTorrents(JSONObject response) throws JSONException { private ArrayList<Torrent> parseJsonTorrents(JSONObject response) throws JSONException {
// Parse response // Parse response
ArrayList<Torrent> torrents = new ArrayList<Torrent>(); ArrayList<Torrent> torrents = new ArrayList<Torrent>();
JSONArray all = response.getJSONArray("torrents"); JSONArray all = response.getJSONArray("torrents");
for (int i = 0; i < all.length(); i++) { for (int i = 0; i < all.length(); i++) {
JSONObject tor = all.getJSONObject(i); JSONObject tor = all.getJSONObject(i);
int leechers = tor.getInt("peers_connected"); int peersConnected = tor.getInt("peers_connected");
int seeders = tor.getInt("seeds_connected"); int seedsConnected = tor.getInt("seeds_connected");
int known = tor.getInt("peers_total") + tor.getInt("seeds_total"); int peersTotal = tor.getInt("peers_total");
int seedsTotal = tor.getInt("seeds_total");
long size = tor.getLong("size"); long size = tor.getLong("size");
long sizeDone = tor.getLong("done"); long sizeDone = tor.getLong("done");
long sizeUp = tor.getLong("payload_upload"); long sizeUp = tor.getLong("payload_upload");
int rateUp = tor.getInt("dl_rate"); int rateUp = tor.getInt("dl_rate");
int rateDown = tor.getInt("ul_rate"); int rateDown = tor.getInt("ul_rate");
// Add the parsed torrent to the list // Add the parsed torrent to the list
// @formatter:off
torrents.add(new Torrent( torrents.add(new Torrent(
(long)i, (long)i,
tor.getString("hash"), tor.getString("hash"),
@ -268,10 +286,10 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
null, null,
rateDown, rateDown,
rateUp, rateUp,
leechers, seedsConnected,
leechers + seeders, seedsTotal,
known, peersConnected,
known, peersTotal,
(rateDown == 0? -1: (int) ((size - sizeDone) / rateDown)), (rateDown == 0? -1: (int) ((size - sizeDone) / rateDown)),
sizeDone, sizeDone,
sizeUp, sizeUp,
@ -283,11 +301,12 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
null, null,
null, null,
settings.getType())); settings.getType()));
// @formatter:on
} }
// Return the list // Return the list
return torrents; return torrents;
} }
private TorrentStatus parseStatus(String state, int stopped) { private TorrentStatus parseStatus(String state, int stopped) {
@ -309,7 +328,7 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
} }
private ArrayList<TorrentFile> parseJsonFiles(JSONObject response, String hash) throws JSONException { private ArrayList<TorrentFile> parseJsonFiles(JSONObject response, String hash) throws JSONException {
// Parse response // Parse response
ArrayList<TorrentFile> torrentfiles = new ArrayList<TorrentFile>(); ArrayList<TorrentFile> torrentfiles = new ArrayList<TorrentFile>();
JSONArray all = response.getJSONObject("torrents").getJSONArray(hash); JSONArray all = response.getJSONObject("torrents").getJSONArray(hash);
@ -317,6 +336,7 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
JSONObject file = all.getJSONObject(i); JSONObject file = all.getJSONObject(i);
long size = file.getLong("size"); long size = file.getLong("size");
long sizeDone = file.getLong("done"); long sizeDone = file.getLong("done");
// @formatter:off
torrentfiles.add(new TorrentFile( torrentfiles.add(new TorrentFile(
"" + file.getInt("id"), "" + file.getInt("id"),
file.getString("name"), file.getString("name"),
@ -325,11 +345,12 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
size, size,
sizeDone, sizeDone,
Priority.Normal)); Priority.Normal));
// @formatter:on
} }
// Return the list // Return the list
return torrentfiles; return torrentfiles;
} }
@Override @Override
@ -341,5 +362,5 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
public DaemonSettings getSettings() { public DaemonSettings getSettings() {
return this.settings; return this.settings;
} }
} }

10
lib/src/org/transdroid/daemon/DLinkRouterBT/DLinkRouterBTAdapter.java

@ -93,8 +93,8 @@ public class DLinkRouterBTAdapter implements IDaemonAdapter {
private static final String BT_PEERS_CONNECTED = "peers_connected"; private static final String BT_PEERS_CONNECTED = "peers_connected";
private static final String BT_PEERS_TOTAL = "peers_total"; private static final String BT_PEERS_TOTAL = "peers_total";
// private static final String BT_PRIVATE = "private"; // private static final String BT_PRIVATE = "private";
// private static final String BT_SEEDS_CONNECTED = "seeds_connected"; private static final String BT_SEEDS_CONNECTED = "seeds_connected";
// private static final String BT_SEEDS_TOTAL = "seeds_total"; private static final String BT_SEEDS_TOTAL = "seeds_total";
private static final String BT_SIZE = "size"; private static final String BT_SIZE = "size";
private static final String BT_STATE = "state"; private static final String BT_STATE = "state";
private static final String BT_STOPPED = "stopped"; private static final String BT_STOPPED = "stopped";
@ -363,9 +363,9 @@ public class DLinkRouterBTAdapter implements IDaemonAdapter {
tor.getInt(BT_DOWNLOAD_RATE), tor.getInt(BT_DOWNLOAD_RATE),
tor.getInt(BT_UPLOAD_RATE), tor.getInt(BT_UPLOAD_RATE),
tor.getInt(BT_PEERS_CONNECTED), tor.getInt(BT_PEERS_CONNECTED),
tor.getInt(BT_PEERS_CONNECTED), tor.getInt(BT_PEERS_TOTAL),
tor.getInt(BT_PEERS_CONNECTED), tor.getInt(BT_SEEDS_CONNECTED),
tor.getInt(BT_PEERS_TOTAL), tor.getInt(BT_SEEDS_TOTAL),
(int) ((tor.getLong(BT_SIZE) - tor.getLong(BT_DONE)) / (tor.getInt(BT_DOWNLOAD_RATE) + 1)), (int) ((tor.getLong(BT_SIZE) - tor.getLong(BT_DONE)) / (tor.getInt(BT_DOWNLOAD_RATE) + 1)),
tor.getLong(BT_DONE), tor.getLong(BT_DONE),
tor.getLong(BT_PAYLOAD_UPLOAD), tor.getLong(BT_PAYLOAD_UPLOAD),

20
lib/src/org/transdroid/daemon/Deluge/DelugeAdapter.java

@ -125,10 +125,10 @@ public class DelugeAdapter implements IDaemonAdapter {
private static final String RPC_RATEDOWNLOAD = "download_payload_rate"; private static final String RPC_RATEDOWNLOAD = "download_payload_rate";
private static final String RPC_RATEUPLOAD = "upload_payload_rate"; private static final String RPC_RATEUPLOAD = "upload_payload_rate";
private static final String RPC_PEERSGETTING = "num_seeds"; private static final String RPC_NUMSEEDS = "num_seeds";
private static final String RPC_PEERSSENDING = "num_seeds"; private static final String RPC_TOTALSEEDS = "total_seeds";
private static final String RPC_PEERSCONNECTED = "num_peers"; private static final String RPC_NUMPEERS = "num_peers";
private static final String RPC_PEERSKNOWN = "total_peers"; private static final String RPC_TOTALPEERS = "total_peers";
private static final String RPC_ETA = "eta"; private static final String RPC_ETA = "eta";
private static final String RPC_TIMEADDED = "time_added"; private static final String RPC_TIMEADDED = "time_added";
@ -149,8 +149,8 @@ public class DelugeAdapter implements IDaemonAdapter {
private static final String[] RPC_FIELDS_ARRAY = new String[] { private static final String[] RPC_FIELDS_ARRAY = new String[] {
RPC_NAME, RPC_STATUS, RPC_SAVEPATH, RPC_RATEDOWNLOAD, RPC_RATEUPLOAD, RPC_NAME, RPC_STATUS, RPC_SAVEPATH, RPC_RATEDOWNLOAD, RPC_RATEUPLOAD,
RPC_PEERSGETTING, RPC_PEERSSENDING, RPC_PEERSCONNECTED, RPC_NUMPEERS, RPC_NUMSEEDS, RPC_TOTALPEERS,
RPC_PEERSKNOWN, RPC_ETA, RPC_DOWNLOADEDEVER, RPC_UPLOADEDEVER, RPC_TOTALSEEDS, RPC_ETA, RPC_DOWNLOADEDEVER, RPC_UPLOADEDEVER,
RPC_TOTALSIZE, RPC_PARTDONE, RPC_LABEL, RPC_MESSAGE, RPC_TIMEADDED, RPC_TRACKER_STATUS }; RPC_TOTALSIZE, RPC_PARTDONE, RPC_LABEL, RPC_MESSAGE, RPC_TIMEADDED, RPC_TRACKER_STATUS };
@ -588,10 +588,10 @@ public class DelugeAdapter implements IDaemonAdapter {
tor.getString(RPC_SAVEPATH) + settings.getOS().getPathSeperator(), tor.getString(RPC_SAVEPATH) + settings.getOS().getPathSeperator(),
tor.getInt(RPC_RATEDOWNLOAD), tor.getInt(RPC_RATEDOWNLOAD),
tor.getInt(RPC_RATEUPLOAD), tor.getInt(RPC_RATEUPLOAD),
tor.getInt(RPC_PEERSGETTING), tor.getInt(RPC_NUMSEEDS),
tor.getInt(RPC_PEERSSENDING), tor.getInt(RPC_TOTALSEEDS),
tor.getInt(RPC_PEERSCONNECTED), tor.getInt(RPC_NUMPEERS),
tor.getInt(RPC_PEERSKNOWN), tor.getInt(RPC_TOTALPEERS),
tor.getInt(RPC_ETA), tor.getInt(RPC_ETA),
tor.getLong(RPC_DOWNLOADEDEVER), tor.getLong(RPC_DOWNLOADEDEVER),
tor.getLong(RPC_UPLOADEDEVER), tor.getLong(RPC_UPLOADEDEVER),

6
lib/src/org/transdroid/daemon/Ktorrent/StatsParser.java

@ -73,10 +73,10 @@ public class StatsParser {
(baseDir == null? null: (numFiles > 0? baseDir + tname + pathSeperator: baseDir)), (baseDir == null? null: (numFiles > 0? baseDir + tname + pathSeperator: baseDir)),
downRate, downRate,
upRate, upRate,
leechers,
seeders, seeders,
seeders + leechers, seedersTotal,
seedersTotal + leechersTotal, leechers,
leechersTotal,
(int) (status == TorrentStatus.Downloading? (total - down) / downRate: -1), // eta (in seconds) = (total_size_in_btes - bytes_already_downloaded) / bytes_per_second (int) (status == TorrentStatus.Downloading? (total - down) / downRate: -1), // eta (in seconds) = (total_size_in_btes - bytes_already_downloaded) / bytes_per_second
down, down,
up, up,

49
lib/src/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java

@ -374,9 +374,8 @@ public class QbittorrentAdapter implements IDaemonAdapter {
ArrayList<Torrent> torrents = new ArrayList<Torrent>(); ArrayList<Torrent> torrents = new ArrayList<Torrent>();
for (int i = 0; i < response.length(); i++) { for (int i = 0; i < response.length(); i++) {
JSONObject tor = response.getJSONObject(i); JSONObject tor = response.getJSONObject(i);
int leechers = parseLeech(tor.getString("num_leechs")); int leechers[] = parsePeers(tor.getString("num_leechs"));
int seeders = parseSeeds(tor.getString("num_seeds")); int seeders[] = parsePeers(tor.getString("num_seeds"));
int known = parseKnown(tor.getString("num_leechs"), tor.getString("num_seeds"));
long size = parseSize(tor.getString("size")); long size = parseSize(tor.getString("size"));
double ratio = parseRatio(tor.getString("ratio")); double ratio = parseRatio(tor.getString("ratio"));
double progress = tor.getDouble("progress"); double progress = tor.getDouble("progress");
@ -387,8 +386,8 @@ public class QbittorrentAdapter implements IDaemonAdapter {
// Date added is only available in /json/propertiesGeneral on a per-torrent basis, unfortunately // Date added is only available in /json/propertiesGeneral on a per-torrent basis, unfortunately
// Add the parsed torrent to the list // Add the parsed torrent to the list
torrents.add(new Torrent((long) i, tor.getString("hash"), tor.getString("name"), parseStatus(tor torrents.add(new Torrent((long) i, tor.getString("hash"), tor.getString("name"), parseStatus(tor
.getString("state")), null, dlspeed, parseSpeed(tor.getString("upspeed")), leechers, leechers .getString("state")), null, dlspeed, parseSpeed(tor.getString("upspeed")), seeders[0], seeders[1],
+ seeders, known, known, (int) eta, (long) (size * progress), (long) (size * ratio), size, leechers[0], leechers[1], (int) eta, (long) (size * progress), (long) (size * ratio), size,
(float) progress, 0f, null, null, null, null, settings.getType())); (float) progress, 0f, null, null, null, null, settings.getType()));
} }
@ -439,41 +438,15 @@ public class QbittorrentAdapter implements IDaemonAdapter {
return (long) number; return (long) number;
} }
private int parseKnown(String leechs, String seeds) { private int[] parsePeers(String seeds) {
// Peers are given in the "num_leechs":"91 (449)","num_seeds":"6 (27)" strings // Peers (seeders or leechers) are defined in a string like "num_seeds":"6 (27)"
// Or sometimes just "num_leechs":"91","num_seeds":"6" strings
// Peers known are in the last () bit of the leechers and seeders
int leechers = 0;
if (leechs.indexOf("(") < 0) {
leechers = Integer.parseInt(leechs);
} else {
leechers = Integer.parseInt(leechs.substring(leechs.indexOf("(") + 1, leechs.indexOf(")")));
}
int seeders = 0;
if (seeds.indexOf("(") < 0) {
seeders = Integer.parseInt(seeds);
} else {
seeders = Integer.parseInt(seeds.substring(seeds.indexOf("(") + 1, seeds.indexOf(")")));
}
return leechers + seeders;
}
private int parseSeeds(String seeds) {
// Seeds are in the first part of the "num_seeds":"6 (27)" string
// In some situations it it just a "6" string // In some situations it it just a "6" string
if (seeds.indexOf(" ") < 0) { String[] parts = seeds.split(" ");
return Integer.parseInt(seeds); if (parts.length > 1) {
} return new int[] { Integer.parseInt(parts[0]),
return Integer.parseInt(seeds.substring(0, seeds.indexOf(" "))); Integer.parseInt(parts[1].substring(1, parts[1].length() - 1)) };
}
private int parseLeech(String leechs) {
// Leechers are in the first part of the "num_leechs":"91 (449)" string
// In some situations it it just a "0" string
if (leechs.indexOf(" ") < 0) {
return Integer.parseInt(leechs);
} }
return Integer.parseInt(leechs.substring(0, leechs.indexOf(" "))); return new int[] { Integer.parseInt(parts[0]), Integer.parseInt(parts[0]) };
} }
private int parseSpeed(String speed) { private int parseSpeed(String speed) {

303
lib/src/org/transdroid/daemon/Rtorrent/RtorrentAdapter.java

@ -69,11 +69,9 @@ import de.timroes.axmlrpc.XMLRPCClient.UnauthorizdException;
import de.timroes.axmlrpc.XMLRPCException; import de.timroes.axmlrpc.XMLRPCException;
/** /**
* An adapter that allows for easy access to rTorrent torrent data. Communication * An adapter that allows for easy access to rTorrent torrent data. Communication is handled via the XML-RPC protocol as
* is handled via the XML-RPC protocol as implemented by the aXMLRPC library. * implemented by the aXMLRPC library.
*
* @author erickok * @author erickok
*
*/ */
public class RtorrentAdapter implements IDaemonAdapter { public class RtorrentAdapter implements IDaemonAdapter {
@ -91,34 +89,79 @@ public class RtorrentAdapter implements IDaemonAdapter {
@Override @Override
public DaemonTaskResult executeTask(DaemonTask task) { public DaemonTaskResult executeTask(DaemonTask task) {
try { try {
switch (task.getMethod()) { switch (task.getMethod()) {
case Retrieve: case Retrieve:
Object result = makeRtorrentCall("d.multicall", new String[] { "main", "d.get_hash=", "d.get_name=", "d.get_state=", "d.get_down_rate=", "d.get_up_rate=", "d.get_peers_connected=", "d.get_peers_not_connected=", "d.get_peers_accounted=", "d.get_bytes_done=", "d.get_up_total=", "d.get_size_bytes=", "d.get_creation_date=", "d.get_left_bytes=", "d.get_complete=", "d.is_active=", "d.is_hash_checking=", "d.get_base_path=", "d.get_base_filename=", "d.get_message=", "d.get_custom=addtime", "d.get_custom=seedingtime", "d.get_custom1=" }); // @formatter:off
Object result = makeRtorrentCall("d.multicall",
new String[] { "main",
"d.get_hash=",
"d.get_name=",
"d.get_state=",
"d.get_down_rate=",
"d.get_up_rate=",
"d.get_peers_connected=",
"d.get_peers_not_connected=",
"d.get_peers_accounted=",
"d.get_bytes_done=",
"d.get_up_total=",
"d.get_size_bytes=",
"d.get_creation_date=",
"d.get_left_bytes=",
"d.get_complete=",
"d.is_active=",
"d.is_hash_checking=",
"d.get_base_path=",
"d.get_base_filename=",
"d.get_message=",
"d.get_custom=addtime",
"d.get_custom=seedingtime",
"d.get_custom1=",
"d.get_peers_complete=",
"d.get_peers_accounted=" });
// @formatter:on
return new RetrieveTaskSuccessResult((RetrieveTask) task, onTorrentsRetrieved(result), lastKnownLabels); return new RetrieveTaskSuccessResult((RetrieveTask) task, onTorrentsRetrieved(result), lastKnownLabels);
case GetTorrentDetails: case GetTorrentDetails:
Object dresult = makeRtorrentCall("t.multicall", new String[] { task.getTargetTorrent().getUniqueID(), "", "t.get_url=" }); // @formatter:off
return new GetTorrentDetailsTaskSuccessResult((GetTorrentDetailsTask) task, onTorrentDetailsRetrieved(dresult)); Object dresult = makeRtorrentCall("t.multicall", new String[] {
task.getTargetTorrent().getUniqueID(),
"",
"t.get_url=" });
// @formatter:on
return new GetTorrentDetailsTaskSuccessResult((GetTorrentDetailsTask) task,
onTorrentDetailsRetrieved(dresult));
case GetFileList: case GetFileList:
Object fresult = makeRtorrentCall("f.multicall", new String[] { task.getTargetTorrent().getUniqueID(), "", "f.get_path=", "f.get_size_bytes=", "f.get_priority=", "f.get_completed_chunks=", "f.get_size_chunks=", "f.get_priority=", "f.get_frozen_path=" }); // @formatter:off
return new GetFileListTaskSuccessResult((GetFileListTask) task, onTorrentFilesRetrieved(fresult, task.getTargetTorrent())); Object fresult = makeRtorrentCall("f.multicall", new String[] {
task.getTargetTorrent().getUniqueID(),
"",
"f.get_path=",
"f.get_size_bytes=",
"f.get_priority=",
"f.get_completed_chunks=",
"f.get_size_chunks=",
"f.get_priority=",
"f.get_frozen_path=" });
// @formatter:on
return new GetFileListTaskSuccessResult((GetFileListTask) task, onTorrentFilesRetrieved(fresult,
task.getTargetTorrent()));
case AddByFile: case AddByFile:
// Request to add a torrent by local .torrent file // Request to add a torrent by local .torrent file
File file = new File(URI.create(((AddByFileTask)task).getFile())); File file = new File(URI.create(((AddByFileTask) task).getFile()));
FileInputStream in = new FileInputStream(file); FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[(int) file.length()]; byte[] buffer = new byte[(int) file.length()];
int read = 0; int read = 0;
while ((read = in.read(buffer, 0, buffer.length)) > 0) { while ((read = in.read(buffer, 0, buffer.length)) > 0) {
baos.write(buffer, 0, read); baos.write(buffer, 0, read);
} }
byte[] bytes = baos.toByteArray(); byte[] bytes = baos.toByteArray();
int size = (int) file.length() * 2; int size = (int) file.length() * 2;
@ -130,19 +173,19 @@ public class RtorrentAdapter implements IDaemonAdapter {
case AddByUrl: case AddByUrl:
// Request to add a torrent by URL // Request to add a torrent by URL
String url = ((AddByUrlTask)task).getUrl(); String url = ((AddByUrlTask) task).getUrl();
makeRtorrentCall("load_start", new String[] { url }); makeRtorrentCall("load_start", new String[] { url });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case AddByMagnetUrl: case AddByMagnetUrl:
// Request to add a magnet link by URL // Request to add a magnet link by URL
String magnet = ((AddByMagnetUrlTask)task).getUrl(); String magnet = ((AddByMagnetUrlTask) task).getUrl();
makeRtorrentCall("load_start", new String[] { magnet }); makeRtorrentCall("load_start", new String[] { magnet });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Remove: case Remove:
// Remove a torrent // Remove a torrent
RemoveTask removeTask = (RemoveTask) task; RemoveTask removeTask = (RemoveTask) task;
if (removeTask.includingData()) { if (removeTask.includingData()) {
@ -150,17 +193,17 @@ public class RtorrentAdapter implements IDaemonAdapter {
} }
makeRtorrentCall("d.erase", new String[] { task.getTargetTorrent().getUniqueID() }); makeRtorrentCall("d.erase", new String[] { task.getTargetTorrent().getUniqueID() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Pause: case Pause:
// Pause a torrent // Pause a torrent
makeRtorrentCall("d.pause", new String[] { task.getTargetTorrent().getUniqueID() }); makeRtorrentCall("d.pause", new String[] { task.getTargetTorrent().getUniqueID() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case PauseAll: case PauseAll:
// Resume all torrents // Resume all torrents
makeRtorrentCall("d.multicall", new String[] { "main", "d.pause=" } ); makeRtorrentCall("d.multicall", new String[] { "main", "d.pause=" });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Resume: case Resume:
@ -168,35 +211,35 @@ public class RtorrentAdapter implements IDaemonAdapter {
// Resume a torrent // Resume a torrent
makeRtorrentCall("d.resume", new String[] { task.getTargetTorrent().getUniqueID() }); makeRtorrentCall("d.resume", new String[] { task.getTargetTorrent().getUniqueID() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case ResumeAll: case ResumeAll:
// Resume all torrents // Resume all torrents
makeRtorrentCall("d.multicall", new String[] { "main", "d.resume=" } ); makeRtorrentCall("d.multicall", new String[] { "main", "d.resume=" });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Stop: case Stop:
// Stop a torrent // Stop a torrent
makeRtorrentCall("d.stop", new String[] { task.getTargetTorrent().getUniqueID() }); makeRtorrentCall("d.stop", new String[] { task.getTargetTorrent().getUniqueID() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case StopAll: case StopAll:
// Stop all torrents // Stop all torrents
makeRtorrentCall("d.multicall", new String[] { "main", "d.stop=" } ); makeRtorrentCall("d.multicall", new String[] { "main", "d.stop=" });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case Start: case Start:
// Start a torrent // Start a torrent
makeRtorrentCall("d.start", new String[] { task.getTargetTorrent().getUniqueID() }); makeRtorrentCall("d.start", new String[] { task.getTargetTorrent().getUniqueID() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case StartAll: case StartAll:
// Start all torrents // Start all torrents
makeRtorrentCall("d.multicall", new String[] { "main", "d.start=" } ); makeRtorrentCall("d.multicall", new String[] { "main", "d.start=" });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case SetFilePriorities: case SetFilePriorities:
@ -206,22 +249,26 @@ public class RtorrentAdapter implements IDaemonAdapter {
String newPriority = "" + convertPriority(prioTask.getNewPriority()); String newPriority = "" + convertPriority(prioTask.getNewPriority());
// One at a time; rTorrent doesn't seem to support a multicall on a selective number of files // One at a time; rTorrent doesn't seem to support a multicall on a selective number of files
for (TorrentFile forFile : prioTask.getForFiles()) { for (TorrentFile forFile : prioTask.getForFiles()) {
makeRtorrentCall("f.set_priority", new String[] { task.getTargetTorrent().getUniqueID() + ":f" + forFile.getKey(), newPriority }); makeRtorrentCall("f.set_priority", new String[] {
task.getTargetTorrent().getUniqueID() + ":f" + forFile.getKey(), newPriority });
} }
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case SetTransferRates: case SetTransferRates:
// Request to set the maximum transfer rates // Request to set the maximum transfer rates
SetTransferRatesTask ratesTask = (SetTransferRatesTask) task; SetTransferRatesTask ratesTask = (SetTransferRatesTask) task;
makeRtorrentCall("set_download_rate", new String[] { (ratesTask.getDownloadRate() == null? "0": ratesTask.getDownloadRate().toString() + "k") }); makeRtorrentCall("set_download_rate", new String[] { (ratesTask.getDownloadRate() == null ? "0"
makeRtorrentCall("set_upload_rate", new String[] { (ratesTask.getUploadRate() == null? "0": ratesTask.getUploadRate().toString() + "k") }); : ratesTask.getDownloadRate().toString() + "k") });
makeRtorrentCall("set_upload_rate", new String[] { (ratesTask.getUploadRate() == null ? "0" : ratesTask
.getUploadRate().toString() + "k") });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case SetLabel: case SetLabel:
SetLabelTask labelTask = (SetLabelTask) task; SetLabelTask labelTask = (SetLabelTask) task;
makeRtorrentCall("d.set_custom1", new String[] { task.getTargetTorrent().getUniqueID(), labelTask.getNewLabel() }); makeRtorrentCall("d.set_custom1",
new String[] { task.getTargetTorrent().getUniqueID(), labelTask.getNewLabel() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
case ForceRecheck: case ForceRecheck:
@ -229,9 +276,10 @@ public class RtorrentAdapter implements IDaemonAdapter {
// Force re-check of data of a torrent // Force re-check of data of a torrent
makeRtorrentCall("d.check_hash", new String[] { task.getTargetTorrent().getUniqueID() }); makeRtorrentCall("d.check_hash", new String[] { task.getTargetTorrent().getUniqueID() });
return new DaemonTaskSuccessResult(task); return new DaemonTaskSuccessResult(task);
default: default:
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not supported by " + getType())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported,
task.getMethod() + " is not supported by " + getType()));
} }
} catch (DaemonException e) { } catch (DaemonException e) {
return new DaemonTaskFailureResult(task, e); return new DaemonTaskFailureResult(task, e);
@ -241,18 +289,22 @@ public class RtorrentAdapter implements IDaemonAdapter {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ConnectionError, e.toString())); return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ConnectionError, e.toString()));
} }
} }
private Object makeRtorrentCall(String serverMethod, Object[] arguments) throws DaemonException, MalformedURLException { private Object makeRtorrentCall(String serverMethod, Object[] arguments) throws DaemonException,
MalformedURLException {
// Initialise the HTTP client // Initialise the HTTP client
if (rpcclient == null) { if (rpcclient == null) {
initialise(); initialise();
} }
String params = ""; String params = "";
for (Object arg : arguments) params += " " + arg.toString(); for (Object arg : arguments)
params += " " + arg.toString();
try { try {
DLog.d(LOG_NAME, "Calling " + serverMethod + " with params [" + (params.length() > 100? params.substring(0, 100) + "...": params) + " ]"); DLog.d(LOG_NAME,
"Calling " + serverMethod + " with params ["
+ (params.length() > 100 ? params.substring(0, 100) + "..." : params) + " ]");
return rpcclient.call(serverMethod, arguments); return rpcclient.call(serverMethod, arguments);
} catch (XMLRPCException e) { } catch (XMLRPCException e) {
DLog.d(LOG_NAME, e.toString()); DLog.d(LOG_NAME, e.toString());
@ -260,9 +312,11 @@ public class RtorrentAdapter implements IDaemonAdapter {
throw new DaemonException(ExceptionType.AuthenticationFailure, e.toString()); throw new DaemonException(ExceptionType.AuthenticationFailure, e.toString());
if (e.getCause() instanceof DaemonException) if (e.getCause() instanceof DaemonException)
throw (DaemonException) e.getCause(); throw (DaemonException) e.getCause();
throw new DaemonException(ExceptionType.ConnectionError, "Error making call to " + serverMethod + " with params [" + (params.length() > 100? params.substring(0, 100) + "...": params) + " ]: " + e.toString()); throw new DaemonException(ExceptionType.ConnectionError, "Error making call to " + serverMethod
+ " with params [" + (params.length() > 100 ? params.substring(0, 100) + "..." : params) + " ]: "
+ e.toString());
} }
} }
/** /**
@ -274,37 +328,42 @@ public class RtorrentAdapter implements IDaemonAdapter {
int flags = XMLRPCClient.FLAGS_8BYTE_INT; int flags = XMLRPCClient.FLAGS_8BYTE_INT;
this.rpcclient = new XMLRPCClient(HttpHelper.createStandardHttpClient(settings, true), buildWebUIUrl(), flags); this.rpcclient = new XMLRPCClient(HttpHelper.createStandardHttpClient(settings, true), buildWebUIUrl(), flags);
} }
/** /**
* Build the URL of rTorrent's XML-RPC location from the user settings. * Build the URL of rTorrent's XML-RPC location from the user settings.
* @return The URL of the RPC API * @return The URL of the RPC API
*/ */
private String buildWebUIUrl() { private String buildWebUIUrl() {
return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + return (settings.getSsl() ? "https://" : "http://")
(settings.getFolder() == null || settings.getFolder().equals("")? DEFAULT_RPC_URL: settings.getFolder()); + settings.getAddress()
+ ":"
+ settings.getPort()
+ (settings.getFolder() == null || settings.getFolder().equals("") ? DEFAULT_RPC_URL : settings
.getFolder());
} }
private List<Torrent> onTorrentsRetrieved(Object response) throws DaemonException { private List<Torrent> onTorrentsRetrieved(Object response) throws DaemonException {
if (response == null || !(response instanceof Object[])) { if (response == null || !(response instanceof Object[])) {
throw new DaemonException(ExceptionType.ParsingFailed, "Response on retrieveing torrents did not return a list of objects"); throw new DaemonException(ExceptionType.ParsingFailed,
"Response on retrieveing torrents did not return a list of objects");
} else { } else {
// Parse torrent list from response // Parse torrent list from response
// Formatted as Object[][], see http://libtorrent.rakshasa.no/wiki/RTorrentCommands#Download // Formatted as Object[][], see http://libtorrent.rakshasa.no/wiki/RTorrentCommands#Download
List<Torrent> torrents = new ArrayList<Torrent>(); List<Torrent> torrents = new ArrayList<Torrent>();
Map<String, Integer> labels = new HashMap<String, Integer>(); Map<String, Integer> labels = new HashMap<String, Integer>();
Object[] responseList = (Object[]) response; Object[] responseList = (Object[]) response;
for (int i = 0; i < responseList.length; i++) { for (int i = 0; i < responseList.length; i++) {
Object[] info = (Object[]) responseList[i]; Object[] info = (Object[]) responseList[i];
String error = (String)info[18]; String error = (String) info[18];
error = error.equals("")? null: error; error = error.equals("") ? null : error;
// Determine the time added // Determine the time added
Date added = null; Date added = null;
Long addtime = null; Long addtime = null;
@ -319,11 +378,11 @@ public class RtorrentAdapter implements IDaemonAdapter {
else { else {
// rTorrent didn't have the addtime (missing plugin?): base it on creationtime instead // rTorrent didn't have the addtime (missing plugin?): base it on creationtime instead
if (info[11] instanceof Long) if (info[11] instanceof Long)
added = new Date((Long)info[11] * 1000L); added = new Date((Long) info[11] * 1000L);
else else
added = new Date((Integer)info[11] * 1000L); added = new Date((Integer) info[11] * 1000L);
} }
// Determine the seeding time // Determine the seeding time
Date finished = null; Date finished = null;
Long seedingtime = null; Long seedingtime = null;
@ -335,26 +394,27 @@ public class RtorrentAdapter implements IDaemonAdapter {
if (seedingtime != null) if (seedingtime != null)
// Successfully received the seedingtime from rTorrent (which is a String like '1337089336\n') // Successfully received the seedingtime from rTorrent (which is a String like '1337089336\n')
finished = new Date(seedingtime * 1000L); finished = new Date(seedingtime * 1000L);
// Determine the label // Determine the label
String label = null; String label = null;
try { try {
label = URLDecoder.decode((String)info[21], "UTF-8"); label = URLDecoder.decode((String) info[21], "UTF-8");
if (labels.containsKey(label)) { if (labels.containsKey(label)) {
labels.put(label, labels.get(label) + 1); labels.put(label, labels.get(label) + 1);
} else { } else {
labels.put(label, 0); labels.put(label, 0);
} }
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
// Can't decode label name; ignore it // Can't decode label name; ignore it
} }
if (info[3] instanceof Long) { if (info[3] instanceof Long) {
// rTorrent uses the i8 dialect which returns 64-bit integers // rTorrent uses the i8 dialect which returns 64-bit integers
long rateDownload = (Long)info[3]; long rateDownload = (Long) info[3];
String basePath = (String)info[16]; String basePath = (String) info[16];
// @formatter:off
torrents.add(new Torrent( torrents.add(new Torrent(
i, i,
(String)info[0], // hash (String)info[0], // hash
@ -363,10 +423,10 @@ public class RtorrentAdapter implements IDaemonAdapter {
basePath.substring(0, basePath.indexOf((String)info[17])), // locationDir basePath.substring(0, basePath.indexOf((String)info[17])), // locationDir
((Long)info[3]).intValue(), // rateDownload ((Long)info[3]).intValue(), // rateDownload
((Long)info[4]).intValue(), // rateUpload ((Long)info[4]).intValue(), // rateUpload
((Long)info[5]).intValue(), // peersGettingFromUs ((Long)info[22]).intValue(), // seedersConnected
((Long)info[5]).intValue(), // peersSendingToUs ((Long)info[5]).intValue() + ((Long)info[6]).intValue(), // seedersKnown
((Long)info[5]).intValue(), // peersConnected ((Long)info[23]).intValue(), // leechersConnected
((Long)info[5]).intValue() + ((Long)info[6]).intValue(), // peersKnown ((Long)info[5]).intValue() + ((Long)info[6]).intValue(), // leechersKnown
(rateDownload > 0? (int) (((Long)info[12]) / rateDownload): -1), // eta (bytes left / rate download, if rate > 0) (rateDownload > 0? (int) (((Long)info[12]) / rateDownload): -1), // eta (bytes left / rate download, if rate > 0)
(Long)info[8], // downloadedEver (Long)info[8], // downloadedEver
(Long)info[9], // uploadedEver (Long)info[9], // uploadedEver
@ -378,13 +438,15 @@ public class RtorrentAdapter implements IDaemonAdapter {
finished, finished,
error, error,
settings.getType())); settings.getType()));
// @formatter:on
} else { } else {
// rTorrent uses the default dialect with 32-bit integers // rTorrent uses the default dialect with 32-bit integers
int rateDownload = (Integer)info[3]; int rateDownload = (Integer) info[3];
String basePath = (String)info[16]; String basePath = (String) info[16];
// @formatter:off
torrents.add(new Torrent( torrents.add(new Torrent(
i, i,
(String)info[0], // hash (String)info[0], // hash
@ -393,10 +455,10 @@ public class RtorrentAdapter implements IDaemonAdapter {
basePath.substring(0, basePath.indexOf((String)info[17])), // locationDir basePath.substring(0, basePath.indexOf((String)info[17])), // locationDir
rateDownload, // rateDownload rateDownload, // rateDownload
(Integer)info[4], // rateUpload (Integer)info[4], // rateUpload
(Integer)info[5], // peersGettingFromUs ((Integer)info[22]).intValue(), // seedersConnected
(Integer)info[5], // peersSendingToUs ((Integer)info[5]).intValue() + ((Integer)info[6]).intValue(), // seedersKnown
(Integer)info[5], // peersConnected ((Integer)info[23]).intValue(), // leechersConnected
(Integer)info[5] + (Integer)info[6], // peersKnown ((Integer)info[5]).intValue() + ((Integer)info[6]).intValue(), // leechersKnown
(rateDownload > 0? (int) ((Integer)info[12] / rateDownload): -1), // eta (bytes left / rate download, if rate > 0) (rateDownload > 0? (int) ((Integer)info[12] / rateDownload): -1), // eta (bytes left / rate download, if rate > 0)
(Integer)info[8], // downloadedEver (Integer)info[8], // downloadedEver
(Integer)info[9], // uploadedEver (Integer)info[9], // uploadedEver
@ -408,7 +470,8 @@ public class RtorrentAdapter implements IDaemonAdapter {
finished, finished,
error, error,
settings.getType())); settings.getType()));
// @formatter:on
} }
} }
lastKnownLabels = new ArrayList<Label>(); lastKnownLabels = new ArrayList<Label>();
@ -417,34 +480,36 @@ public class RtorrentAdapter implements IDaemonAdapter {
lastKnownLabels.add(new Label(pair.getKey(), pair.getValue())); lastKnownLabels.add(new Label(pair.getKey(), pair.getValue()));
} }
return torrents; return torrents;
} }
} }
private List<TorrentFile> onTorrentFilesRetrieved(Object response, Torrent torrent) throws DaemonException { private List<TorrentFile> onTorrentFilesRetrieved(Object response, Torrent torrent) throws DaemonException {
if (response == null || !(response instanceof Object[])) { if (response == null || !(response instanceof Object[])) {
throw new DaemonException(ExceptionType.ParsingFailed, "Response on retrieveing torrent files did not return a list of objects"); throw new DaemonException(ExceptionType.ParsingFailed,
"Response on retrieveing torrent files did not return a list of objects");
} else { } else {
// Parse torrent files from response // Parse torrent files from response
// Formatted as Object[][], see http://libtorrent.rakshasa.no/wiki/RTorrentCommands#Download // Formatted as Object[][], see http://libtorrent.rakshasa.no/wiki/RTorrentCommands#Download
List<TorrentFile> files= new ArrayList<TorrentFile>(); List<TorrentFile> files = new ArrayList<TorrentFile>();
Object[] responseList = (Object[]) response; Object[] responseList = (Object[]) response;
for (int i = 0; i < responseList.length; i++) { for (int i = 0; i < responseList.length; i++) {
Object[] info = (Object[]) responseList[i]; Object[] info = (Object[]) responseList[i];
if (info[1] instanceof Long) { if (info[1] instanceof Long) {
// rTorrent uses the i8 dialect which returns 64-bit integers // rTorrent uses the i8 dialect which returns 64-bit integers
Long size = (Long)info[1]; Long size = (Long) info[1];
Long chunksDone = (Long)info[3]; Long chunksDone = (Long) info[3];
Long chunksTotal = (Long)info[4]; Long chunksTotal = (Long) info[4];
Long priority = (Long)info[5]; Long priority = (Long) info[5];
// @formatter:off
files.add(new TorrentFile( files.add(new TorrentFile(
"" + i, "" + i,
(String)info[0], // name (String)info[0], // name
@ -453,16 +518,17 @@ public class RtorrentAdapter implements IDaemonAdapter {
size, // size size, // size
(long) (size * ((float)chunksDone / (float)chunksTotal)), // done (long) (size * ((float)chunksDone / (float)chunksTotal)), // done
convertRtorrentPriority(priority.intValue()))); // priority convertRtorrentPriority(priority.intValue()))); // priority
//(Long)info[2] has priority // @formatter:on
} else { } else {
// rTorrent uses the default dialect with 32-bit integers // rTorrent uses the default dialect with 32-bit integers
Integer size = (Integer)info[1]; Integer size = (Integer) info[1];
Integer chunksDone = (Integer)info[3]; Integer chunksDone = (Integer) info[3];
Integer chunksTotal = (Integer)info[4]; Integer chunksTotal = (Integer) info[4];
Integer priority = (Integer)info[5]; Integer priority = (Integer) info[5];
// @formatter:off
files.add(new TorrentFile( files.add(new TorrentFile(
"" + i, "" + i,
(String)info[0], // name (String)info[0], // name
@ -471,14 +537,14 @@ public class RtorrentAdapter implements IDaemonAdapter {
size, // size size, // size
(int) (size * ((float)chunksDone / (float)chunksTotal)), // done (int) (size * ((float)chunksDone / (float)chunksTotal)), // done
convertRtorrentPriority(priority))); // priority convertRtorrentPriority(priority))); // priority
//(Long)info[2] has priority // @formatter:on
} }
} }
return files; return files;
} }
} }
private Priority convertRtorrentPriority(int code) { private Priority convertRtorrentPriority(int code) {
@ -522,29 +588,30 @@ public class RtorrentAdapter implements IDaemonAdapter {
} }
private TorrentDetails onTorrentDetailsRetrieved(Object response) throws DaemonException { private TorrentDetails onTorrentDetailsRetrieved(Object response) throws DaemonException {
if (response == null || !(response instanceof Object[])) { if (response == null || !(response instanceof Object[])) {
throw new DaemonException(ExceptionType.ParsingFailed, "Response on retrieveing trackers did not return a list of objects"); throw new DaemonException(ExceptionType.ParsingFailed,
"Response on retrieveing trackers did not return a list of objects");
} else { } else {
// Parse a torrent's trackers from response // Parse a torrent's trackers from response
// Formatted as Object[][], see http://libtorrent.rakshasa.no/wiki/RTorrentCommands#Download // Formatted as Object[][], see http://libtorrent.rakshasa.no/wiki/RTorrentCommands#Download
List<String> trackers = new ArrayList<String>(); List<String> trackers = new ArrayList<String>();
Object[] responseList = (Object[]) response; Object[] responseList = (Object[]) response;
try { try {
for (int i = 0; i < responseList.length; i++) { for (int i = 0; i < responseList.length; i++) {
Object[] info = (Object[]) responseList[i]; Object[] info = (Object[]) responseList[i];
trackers.add((String) info[0]); trackers.add((String) info[0]);
} }
} catch (Exception e) { } catch (Exception e) {
DLog.e(LOG_NAME, e.toString()); DLog.e(LOG_NAME, e.toString());
} }
return new TorrentDetails(trackers, null); return new TorrentDetails(trackers, null);
} }
} }
@Override @Override
@ -556,5 +623,5 @@ public class RtorrentAdapter implements IDaemonAdapter {
public DaemonSettings getSettings() { public DaemonSettings getSettings() {
return this.settings; return this.settings;
} }
} }

13
lib/src/org/transdroid/daemon/Synology/SynologyAdapter.java

@ -294,14 +294,15 @@ public class SynologyAdapter implements IDaemonAdapter {
int speed = transfer.getInt("speed_download"); int speed = transfer.getInt("speed_download");
long size = jsonTorrent.getLong("size"); long size = jsonTorrent.getLong("size");
Float eta = new Float(size - downloaded) / speed; Float eta = new Float(size - downloaded) / speed;
int totalPeers = 0; int totalSeeders = 0;
int totalLeechers = 0;
if (additional.has("tracker")) { if (additional.has("tracker")) {
JSONArray tracker = additional.getJSONArray("tracker"); JSONArray tracker = additional.getJSONArray("tracker");
for (int i = 0; i < tracker.length(); i++) { for (int i = 0; i < tracker.length(); i++) {
JSONObject t = tracker.getJSONObject(i); JSONObject t = tracker.getJSONObject(i);
if ("Success".equals(t.getString("status"))) { if ("Success".equals(t.getString("status"))) {
totalPeers += t.getInt("peers"); totalLeechers += t.getInt("peers");
totalPeers += t.getInt("seeds"); totalSeeders += t.getInt("seeds");
} }
} }
} }
@ -313,10 +314,10 @@ public class SynologyAdapter implements IDaemonAdapter {
detail.getString("destination"), detail.getString("destination"),
speed, speed,
transfer.getInt("speed_upload"), transfer.getInt("speed_upload"),
detail.getInt("connected_leechers"),
detail.getInt("connected_seeders"), detail.getInt("connected_seeders"),
totalPeers, totalSeeders,
totalPeers, detail.getInt("connected_leechers"),
totalLeechers,
eta.intValue(), eta.intValue(),
downloaded, downloaded,
transfer.getLong("size_uploaded"), transfer.getLong("size_uploaded"),

211
lib/src/org/transdroid/daemon/Torrent.java

@ -15,7 +15,7 @@
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>. * along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
package org.transdroid.daemon; package org.transdroid.daemon;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -25,9 +25,7 @@ import android.os.Parcelable;
/** /**
* Represents a torrent on a server daemon. * Represents a torrent on a server daemon.
*
* @author erickok * @author erickok
*
*/ */
public final class Torrent implements Parcelable, Comparable<Torrent>, Finishable { public final class Torrent implements Parcelable, Comparable<Torrent>, Finishable {
@ -36,15 +34,15 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
final private String name; final private String name;
private TorrentStatus statusCode; private TorrentStatus statusCode;
private String locationDir; private String locationDir;
final private int rateDownload; final private int rateDownload;
final private int rateUpload; final private int rateUpload;
final private int peersGettingFromUs; final private int seedersConnected;
final private int peersSendingToUs; final private int seedersKnown;
final private int peersConnected; final private int leechersConnected;
final private int peersKnown; final private int leechersKnown;
final private int eta; final private int eta;
final private long downloadedEver; final private long downloadedEver;
final private long uploadedEver; final private long uploadedEver;
final private long totalSize; final private long totalSize;
@ -56,48 +54,22 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
final private Date dateDone; final private Date dateDone;
final private String error; final private String error;
final private Daemon daemon; final private Daemon daemon;
//public long getID() { return id; }
//public String getHash() { return hash; }
public String getName() { return name; }
public TorrentStatus getStatusCode() { return statusCode; }
public String getLocationDir() { return locationDir; }
public int getRateDownload() { return rateDownload; }
public int getRateUpload() { return rateUpload; }
public int getPeersGettingFromUs() { return peersGettingFromUs; }
public int getPeersSendingToUs() { return peersSendingToUs; }
public int getPeersConnected() { return peersConnected; }
public int getPeersKnown() { return peersKnown; }
public int getEta() { return eta; }
public long getDownloadedEver() { return downloadedEver; }
public long getUploadedEver() { return uploadedEver; }
public long getTotalSize() { return totalSize; }
public float getPartDone() { return partDone; }
public float getAvailability() { return available; }
public String getLabelName() { return label; }
public Date getDateAdded() { return dateAdded; }
public Date getDateDone() { return dateDone; }
public String getError() { return error; }
public Daemon getDaemon() { return daemon; }
private Torrent(Parcel in) { private Torrent(Parcel in) {
this.id = in.readLong(); this.id = in.readLong();
this.hash = in.readString(); this.hash = in.readString();
this.name = in.readString(); this.name = in.readString();
this.statusCode = TorrentStatus.getStatus(in.readInt()); this.statusCode = TorrentStatus.getStatus(in.readInt());
this.locationDir = in.readString(); this.locationDir = in.readString();
this.rateDownload = in.readInt(); this.rateDownload = in.readInt();
this.rateUpload = in.readInt(); this.rateUpload = in.readInt();
this.peersGettingFromUs = in.readInt(); this.seedersConnected = in.readInt();
this.peersSendingToUs = in.readInt(); this.seedersKnown = in.readInt();
this.peersConnected = in.readInt(); this.leechersConnected = in.readInt();
this.peersKnown = in.readInt(); this.leechersKnown = in.readInt();
this.eta = in.readInt(); this.eta = in.readInt();
this.downloadedEver = in.readLong(); this.downloadedEver = in.readLong();
this.uploadedEver = in.readLong(); this.uploadedEver = in.readLong();
this.totalSize = in.readLong(); this.totalSize = in.readLong();
@ -106,38 +78,38 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
this.label = in.readString(); this.label = in.readString();
long lDateAdded = in.readLong(); long lDateAdded = in.readLong();
this.dateAdded = (lDateAdded == -1)? null: new Date(lDateAdded); this.dateAdded = (lDateAdded == -1) ? null : new Date(lDateAdded);
long lDateDone = in.readLong(); long lDateDone = in.readLong();
this.dateDone = (lDateDone == -1)? null: new Date(lDateDone); this.dateDone = (lDateDone == -1) ? null : new Date(lDateDone);
this.error = in.readString(); this.error = in.readString();
this.daemon = Daemon.valueOf(in.readString()); this.daemon = Daemon.valueOf(in.readString());
} }
public Torrent(long id, String hash, String name, TorrentStatus statusCode, String locationDir, int rateDownload, int rateUpload, public Torrent(long id, String hash, String name, TorrentStatus statusCode, String locationDir, int rateDownload,
int peersGettingFromUs, int peersSendingToUs, int peersConnected, int peersKnown, int eta, int rateUpload, int seedersConnected, int seedersKnown, int leechersConnected, int leechersKnown, int eta,
long downloadedEver, long uploadedEver, long totalSize, float partDone, float available, String label, long downloadedEver, long uploadedEver, long totalSize, float partDone, float available, String label,
Date dateAdded, Date realDateDone, String error, Daemon daemon) { Date dateAdded, Date realDateDone, String error, Daemon daemon) {
this.id = id; this.id = id;
this.hash = hash; this.hash = hash;
this.name = name; this.name = name;
this.statusCode = statusCode; this.statusCode = statusCode;
this.locationDir = locationDir; this.locationDir = locationDir;
this.rateDownload = rateDownload; this.rateDownload = rateDownload;
this.rateUpload = rateUpload; this.rateUpload = rateUpload;
this.peersGettingFromUs = peersGettingFromUs; this.seedersConnected = seedersConnected;
this.peersSendingToUs = peersSendingToUs; this.seedersKnown = seedersKnown;
this.peersConnected = peersConnected; this.leechersConnected = leechersConnected;
this.peersKnown = peersKnown; this.leechersKnown = leechersKnown;
this.eta = eta; this.eta = eta;
this.downloadedEver = downloadedEver; this.downloadedEver = downloadedEver;
this.uploadedEver = uploadedEver; this.uploadedEver = uploadedEver;
this.totalSize = totalSize; this.totalSize = totalSize;
this.partDone = partDone; this.partDone = partDone;
this.available = available; this.available = available;
this.label = label; this.label = label;
this.dateAdded = dateAdded; this.dateAdded = dateAdded;
if (realDateDone != null) { if (realDateDone != null) {
this.dateDone = realDateDone; this.dateDone = realDateDone;
@ -160,7 +132,87 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
this.error = error; this.error = error;
this.daemon = daemon; this.daemon = daemon;
} }
public String getName() {
return name;
}
public TorrentStatus getStatusCode() {
return statusCode;
}
public String getLocationDir() {
return locationDir;
}
public int getRateDownload() {
return rateDownload;
}
public int getRateUpload() {
return rateUpload;
}
public int getSeedersConnected() {
return seedersConnected;
}
public int getSeedersKnown() {
return seedersKnown;
}
public int getLeechersConnected() {
return leechersConnected;
}
public int getLeechersKnown() {
return leechersKnown;
}
public int getEta() {
return eta;
}
public long getDownloadedEver() {
return downloadedEver;
}
public long getUploadedEver() {
return uploadedEver;
}
public long getTotalSize() {
return totalSize;
}
public float getPartDone() {
return partDone;
}
public float getAvailability() {
return available;
}
public String getLabelName() {
return label;
}
public Date getDateAdded() {
return dateAdded;
}
public Date getDateDone() {
return dateDone;
}
public String getError() {
return error;
}
public Daemon getDaemon() {
return daemon;
}
/** /**
* Returns the torrent-specific ID, which is the torrent's hash or (if not available) the long number * Returns the torrent-specific ID, which is the torrent's hash or (if not available) the long number
* @return The torrent's (session-transient) unique ID * @return The torrent's (session-transient) unique ID
@ -174,11 +226,11 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
} }
/** /**
* Gives the upload/download seed ratio. * Gives the upload/download seed ratio.
* @return The ratio in range [0,r] * @return The ratio in range [0,r]
*/ */
public double getRatio() { public double getRatio() {
return ((double)uploadedEver) / ((double)downloadedEver); return ((double) uploadedEver) / ((double) downloadedEver);
} }
/** /**
@ -258,7 +310,8 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
*/ */
public boolean canStop() { public boolean canStop() {
// Can stop when it is downloading or seeding or paused // Can stop when it is downloading or seeding or paused
return statusCode == TorrentStatus.Downloading || statusCode == TorrentStatus.Seeding || statusCode == TorrentStatus.Paused; return statusCode == TorrentStatus.Downloading || statusCode == TorrentStatus.Seeding
|| statusCode == TorrentStatus.Paused;
} }
public void mimicResume() { public void mimicResume() {
@ -288,7 +341,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
public void mimicNewLabel(String newLabel) { public void mimicNewLabel(String newLabel) {
label = newLabel; label = newLabel;
} }
public void mimicCheckingStatus() { public void mimicCheckingStatus() {
statusCode = TorrentStatus.Checking; statusCode = TorrentStatus.Checking;
} }
@ -296,34 +349,34 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
public void mimicNewLocation(String newLocation) { public void mimicNewLocation(String newLocation) {
locationDir = newLocation; locationDir = newLocation;
} }
@Override @Override
public String toString() { public String toString() {
// (HASH_OR_ID) NAME // (HASH_OR_ID) NAME
return "(" + ((hash != null)? hash: String.valueOf(id)) + ") " + name; return "(" + ((hash != null) ? hash : String.valueOf(id)) + ") " + name;
} }
@Override @Override
public int compareTo(Torrent another) { public int compareTo(Torrent another) {
// Compare torrent objects on their name (used for sorting only!) // Compare torrent objects on their name (used for sorting only!)
return name.compareTo(another.getName()); return name.compareTo(another.getName());
} }
public static final Parcelable.Creator<Torrent> CREATOR = new Parcelable.Creator<Torrent>() { public static final Parcelable.Creator<Torrent> CREATOR = new Parcelable.Creator<Torrent>() {
public Torrent createFromParcel(Parcel in) { public Torrent createFromParcel(Parcel in) {
return new Torrent(in); return new Torrent(in);
} }
public Torrent[] newArray(int size) { public Torrent[] newArray(int size) {
return new Torrent[size]; return new Torrent[size];
} }
}; };
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
} }
@Override @Override
public void writeToParcel(Parcel dest, int flags) { public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id); dest.writeLong(id);
@ -334,12 +387,12 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
dest.writeInt(rateDownload); dest.writeInt(rateDownload);
dest.writeInt(rateUpload); dest.writeInt(rateUpload);
dest.writeInt(peersGettingFromUs); dest.writeInt(seedersConnected);
dest.writeInt(peersSendingToUs); dest.writeInt(seedersKnown);
dest.writeInt(peersConnected); dest.writeInt(leechersConnected);
dest.writeInt(peersKnown); dest.writeInt(leechersKnown);
dest.writeInt(eta); dest.writeInt(eta);
dest.writeLong(downloadedEver); dest.writeLong(downloadedEver);
dest.writeLong(uploadedEver); dest.writeLong(uploadedEver);
dest.writeLong(totalSize); dest.writeLong(totalSize);
@ -347,10 +400,10 @@ public final class Torrent implements Parcelable, Comparable<Torrent>, Finishabl
dest.writeFloat(available); dest.writeFloat(available);
dest.writeString(label); dest.writeString(label);
dest.writeLong((dateAdded == null)? -1: dateAdded.getTime()); dest.writeLong((dateAdded == null) ? -1 : dateAdded.getTime());
dest.writeLong((dateDone == null)? -1: dateDone.getTime()); dest.writeLong((dateDone == null) ? -1 : dateDone.getTime());
dest.writeString(error); dest.writeString(error);
dest.writeString(daemon.name()); dest.writeString(daemon.name());
} }
} }

3
lib/src/org/transdroid/daemon/Transmission/TransmissionAdapter.java

@ -95,7 +95,6 @@ public class TransmissionAdapter implements IDaemonAdapter {
private static final String RPC_PEERSGETTING = "peersGettingFromUs"; private static final String RPC_PEERSGETTING = "peersGettingFromUs";
private static final String RPC_PEERSSENDING = "peersSendingToUs"; private static final String RPC_PEERSSENDING = "peersSendingToUs";
private static final String RPC_PEERSCONNECTED = "peersConnected"; private static final String RPC_PEERSCONNECTED = "peersConnected";
//private static final String RPC_PEERSKNOWN = "peersKnown";
private static final String RPC_ETA = "eta"; private static final String RPC_ETA = "eta";
private static final String RPC_DOWNLOADSIZE1 = "haveUnchecked"; private static final String RPC_DOWNLOADSIZE1 = "haveUnchecked";
private static final String RPC_DOWNLOADSIZE2 = "haveValid"; private static final String RPC_DOWNLOADSIZE2 = "haveValid";
@ -504,9 +503,9 @@ public class TransmissionAdapter implements IDaemonAdapter {
locationDir, locationDir,
tor.getInt(RPC_RATEDOWNLOAD), tor.getInt(RPC_RATEDOWNLOAD),
tor.getInt(RPC_RATEUPLOAD), tor.getInt(RPC_RATEUPLOAD),
tor.getInt(RPC_PEERSGETTING),
tor.getInt(RPC_PEERSSENDING), tor.getInt(RPC_PEERSSENDING),
tor.getInt(RPC_PEERSCONNECTED), tor.getInt(RPC_PEERSCONNECTED),
tor.getInt(RPC_PEERSGETTING),
tor.getInt(RPC_PEERSCONNECTED), tor.getInt(RPC_PEERSCONNECTED),
tor.getInt(RPC_ETA), tor.getInt(RPC_ETA),
tor.getLong(RPC_DOWNLOADSIZE1) + tor.getLong(RPC_DOWNLOADSIZE2), tor.getLong(RPC_DOWNLOADSIZE1) + tor.getLong(RPC_DOWNLOADSIZE2),

4
lib/src/org/transdroid/daemon/Utorrent/UtorrentAdapter.java

@ -516,9 +516,9 @@ public class UtorrentAdapter implements IDaemonAdapter {
tor.getInt(RPC_DOWNLOADSPEED_IDX), tor.getInt(RPC_DOWNLOADSPEED_IDX),
tor.getInt(RPC_UPLOADSPEED_IDX), tor.getInt(RPC_UPLOADSPEED_IDX),
tor.getInt(RPC_SEEDSCONNECTED_IDX), tor.getInt(RPC_SEEDSCONNECTED_IDX),
tor.getInt(RPC_SEEDSINSWARM_IDX),
tor.getInt(RPC_PEERSCONNECTED_IDX), tor.getInt(RPC_PEERSCONNECTED_IDX),
(downloaded? tor.getInt(RPC_SEEDSINSWARM_IDX): tor.getInt(RPC_PEERSINSWARM_IDX)), tor.getInt(RPC_PEERSINSWARM_IDX),
0, // Not available
tor.getInt(RPC_ETA_IDX), tor.getInt(RPC_ETA_IDX),
tor.getLong(RPC_DOWNLOADED_IDX), tor.getLong(RPC_DOWNLOADED_IDX),
tor.getLong(RPC_UPLOADED_IDX), tor.getLong(RPC_UPLOADED_IDX),

8
lib/src/org/transdroid/daemon/Vuze/VuzeAdapter.java

@ -402,10 +402,10 @@ public class VuzeAdapter implements IDaemonAdapter {
(String) statsinfo.get("target_file_or_dir") + "/", // locationDir (String) statsinfo.get("target_file_or_dir") + "/", // locationDir
rateDownload, // rateDownload rateDownload, // rateDownload
((Long)statsinfo.get("upload_average")).intValue(), // rateUpload ((Long)statsinfo.get("upload_average")).intValue(), // rateUpload
announceSeedCount, // peersGettingFromUs announceSeedCount, // seedersConnected
announceNonSeedCount, // peersSendingToUs scrapeSeedCount, // seedersKnown
scrapeSeedCount + scrapeNonSeedCount, // peersConnected announceNonSeedCount, // leechersConnected
scrapeSeedCount + scrapeNonSeedCount, // peersKnown scrapeNonSeedCount, // leechersKnown
(rateDownload > 0? (int)((Long)statsinfo.get("remaining") / rateDownload): -1), // eta (bytes left / rate download, if rate > 0) (rateDownload > 0? (int)((Long)statsinfo.get("remaining") / rateDownload): -1), // eta (bytes left / rate download, if rate > 0)
(Long)statsinfo.get("downloaded"), // downloadedEver (Long)statsinfo.get("downloaded"), // downloadedEver
(Long)statsinfo.get("uploaded"), // uploadedEver (Long)statsinfo.get("uploaded"), // uploadedEver

Loading…
Cancel
Save