/* * This file is part of Transdroid * * Transdroid 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. * * Transdroid 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 Transdroid. If not, see . * */ package org.transdroid.daemon.Deluge; import com.android.internalcopy.http.multipart.FilePart; import com.android.internalcopy.http.multipart.MultipartEntity; import com.android.internalcopy.http.multipart.Part; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.cookie.Cookie; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.HTTP; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.transdroid.core.gui.log.Log; import org.transdroid.daemon.Daemon; import org.transdroid.daemon.DaemonException; import org.transdroid.daemon.DaemonException.ExceptionType; import org.transdroid.daemon.DaemonSettings; import org.transdroid.daemon.IDaemonAdapter; import org.transdroid.daemon.Label; import org.transdroid.daemon.Priority; import org.transdroid.daemon.Torrent; import org.transdroid.daemon.TorrentDetails; import org.transdroid.daemon.TorrentFile; import org.transdroid.daemon.TorrentStatus; import org.transdroid.daemon.task.AddByFileTask; import org.transdroid.daemon.task.AddByMagnetUrlTask; import org.transdroid.daemon.task.AddByUrlTask; import org.transdroid.daemon.task.DaemonTask; import org.transdroid.daemon.task.DaemonTaskFailureResult; import org.transdroid.daemon.task.DaemonTaskResult; import org.transdroid.daemon.task.DaemonTaskSuccessResult; import org.transdroid.daemon.task.GetFileListTask; import org.transdroid.daemon.task.GetFileListTaskSuccessResult; import org.transdroid.daemon.task.GetTorrentDetailsTask; import org.transdroid.daemon.task.GetTorrentDetailsTaskSuccessResult; import org.transdroid.daemon.task.PauseTask; import org.transdroid.daemon.task.RemoveTask; import org.transdroid.daemon.task.ResumeTask; import org.transdroid.daemon.task.RetrieveTask; import org.transdroid.daemon.task.RetrieveTaskSuccessResult; import org.transdroid.daemon.task.SetDownloadLocationTask; import org.transdroid.daemon.task.SetFilePriorityTask; import org.transdroid.daemon.task.SetLabelTask; import org.transdroid.daemon.task.SetTrackersTask; import org.transdroid.daemon.task.SetTransferRatesTask; import org.transdroid.daemon.util.HttpHelper; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.ArrayList; import java.util.Date; import java.util.List; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DETAILS_FIELDS_ARRAY; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_DOWNLOADEDEVER; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_ETA; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FIELDS_ARRAY; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILEPRIORITIES; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILEPROGRESS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILE_FIELDS_ARRAY; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_INDEX; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_LABEL; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MAXDOWNLOAD; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MAXUPLOAD; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MESSAGE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD_FILE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD_MAGNET; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_AUTH_LOGIN; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_FORCERECHECK; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_MOVESTORAGE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_PAUSE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_PAUSE_ALL; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_REMOVE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_RESUME; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_RESUME_ALL; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETCONFIG; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETFILE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETLABEL; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETTRACKERS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_STATUS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_NAME; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_NUMPEERS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_NUMSEEDS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PARAMS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PARTDONE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PATH; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RATEDOWNLOAD; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RATEUPLOAD; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RESULT; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SAVEPATH; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SESSION_ID; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SIZE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_STATUS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TIER; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TIMEADDED; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TORRENTS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALPEERS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALSEEDS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TOTALSIZE; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKERS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_TRACKER_STATUS; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_UPLOADEDEVER; import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL; /** * The daemon adapter from the Deluge torrent client. * @author erickok */ public class DelugeAdapter implements IDaemonAdapter { private static final String LOG_NAME = "Deluge daemon"; private static final String PATH_TO_RPC = "/json"; private static final String PATH_TO_UPLOAD = "/upload"; private static final String RPC_ID = "id"; private DaemonSettings settings; private DefaultHttpClient httpclient; private Cookie sessionCookie; private int version = -1; public DelugeAdapter(DaemonSettings settings) { this.settings = settings; } public JSONArray addTorrentByFile(String file, Log log) throws JSONException, IOException, DaemonException { String url = buildWebUIUrl() + PATH_TO_UPLOAD; log.d(LOG_NAME, "Uploading a file to the Deluge daemon: " + url); // Initialise the HTTP client if (httpclient == null) { initialise(); } // Setup client using POST HttpPost httppost = new HttpPost(url); File upload = new File(URI.create(file)); Part[] parts = {new FilePart(RPC_FILE, upload)}; httppost.setEntity(new MultipartEntity(parts, httppost.getParams())); // Make request HttpResponse response = httpclient.execute(httppost); // Read JSON response InputStream instream = response.getEntity().getContent(); String result = HttpHelper.convertStreamToString(instream); // If the upload succeeded, add the torrent file on the server // For this we need the file name, which is now send as a JSON object like: // {"files": ["/tmp/delugeweb/tmp00000.torrent"], "success": true} String remoteFile = (new JSONObject(result)).getJSONArray(RPC_DETAILS).getString(0); JSONArray params = new JSONArray(); JSONArray files = new JSONArray(); JSONObject fileu = new JSONObject(); fileu.put("path", remoteFile); fileu.put("options", new JSONArray()); files.put(fileu); params.put(files); return params; } @Override public DaemonTaskResult executeTask(Log log, DaemonTask task) { try { ensureVersion(log); JSONArray params = new JSONArray(); // Array of the fields needed for files listing calls JSONArray ffields = new JSONArray(); for (String field : RPC_FILE_FIELDS_ARRAY) { ffields.put(field); } switch (task.getMethod()) { case Retrieve: // Request all torrents from server JSONArray fields = new JSONArray(); for (String field : RPC_FIELDS_ARRAY) { fields.put(field); } params.put(fields); // keys params.put(new JSONArray()); // filter_dict // params.put(-1); // cache_id JSONObject result = makeRequest(buildRequest(RPC_METHOD_GET, params), log); return new RetrieveTaskSuccessResult((RetrieveTask) task, parseJsonRetrieveTorrents(result.getJSONObject(RPC_RESULT)), parseJsonRetrieveLabels(result.getJSONObject(RPC_RESULT))); case GetTorrentDetails: // Array of the fields needed for files listing calls JSONArray dfields = new JSONArray(); for (String field : RPC_DETAILS_FIELDS_ARRAY) { dfields.put(field); } // Request file listing of a torrent params.put(task.getTargetTorrent().getUniqueID()); // torrent_id params.put(dfields); // keys JSONObject dinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log); return new GetTorrentDetailsTaskSuccessResult((GetTorrentDetailsTask) task, parseJsonTorrentDetails(dinfo.getJSONObject (RPC_RESULT))); case GetFileList: // Request file listing of a torrent params.put(task.getTargetTorrent().getUniqueID()); // torrent_id params.put(ffields); // keys JSONObject finfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log); return new GetFileListTaskSuccessResult((GetFileListTask) task, parseJsonFileListing(finfo.getJSONObject(RPC_RESULT), task .getTargetTorrent())); case AddByFile: // Request to add a torrent by local .torrent file String file = ((AddByFileTask) task).getFile(); makeRequest(buildRequest(RPC_METHOD_ADD_FILE, addTorrentByFile(file, log)), log); return new DaemonTaskSuccessResult(task); case AddByUrl: // Request to add a torrent by URL String url = ((AddByUrlTask) task).getUrl(); params.put(url); params.put(new JSONArray()); makeRequest(buildRequest(RPC_METHOD_ADD, params), log); return new DaemonTaskSuccessResult(task); case AddByMagnetUrl: // Request to add a magnet link by URL String magnet = ((AddByMagnetUrlTask) task).getUrl(); params.put(magnet); params.put(new JSONArray()); makeRequest(buildRequest(RPC_METHOD_ADD_MAGNET, params), log); return new DaemonTaskSuccessResult(task); case Remove: // Remove a torrent RemoveTask removeTask = (RemoveTask) task; params.put(removeTask.getTargetTorrent().getUniqueID()); params.put(removeTask.includingData()); makeRequest(buildRequest(RPC_METHOD_REMOVE, params), log); return new DaemonTaskSuccessResult(task); case Pause: // Pause a torrent PauseTask pauseTask = (PauseTask) task; makeRequest(buildRequest(RPC_METHOD_PAUSE, ((new JSONArray()).put((new JSONArray()).put(pauseTask.getTargetTorrent().getUniqueID ())))), log); return new DaemonTaskSuccessResult(task); case PauseAll: // Resume all torrents makeRequest(buildRequest(RPC_METHOD_PAUSE_ALL, null), log); return new DaemonTaskSuccessResult(task); case Resume: // Resume a torrent ResumeTask resumeTask = (ResumeTask) task; makeRequest(buildRequest(RPC_METHOD_RESUME, ((new JSONArray()).put((new JSONArray()).put(resumeTask.getTargetTorrent() .getUniqueID())))), log); return new DaemonTaskSuccessResult(task); case ResumeAll: // Resume all torrents makeRequest(buildRequest(RPC_METHOD_RESUME_ALL, null), log); return new DaemonTaskSuccessResult(task); case SetFilePriorities: // Set the priorities of files in a specific torrent SetFilePriorityTask prioTask = (SetFilePriorityTask) task; // We first need a listing of all the files (because we can only set the priorities all at once) params.put(task.getTargetTorrent().getUniqueID()); // torrent_id params.put(ffields); // keys JSONObject pinfo = makeRequest(buildRequest(RPC_METHOD_STATUS, params), log); ArrayList pfiles = parseJsonFileListing(pinfo.getJSONObject(RPC_RESULT), prioTask.getTargetTorrent()); // Now prepare the new list of priorities params = new JSONArray(); params.put(task.getTargetTorrent().getUniqueID()); // torrent_id JSONArray pfields = new JSONArray(); // Override the priorities in the just retrieved list of all files for (TorrentFile pfile : pfiles) { Priority newPriority = pfile.getPriority(); for (TorrentFile forFile : prioTask.getForFiles()) { if (forFile.getKey().equals(pfile.getKey())) { // This is a file that we want to assign a new priority to newPriority = prioTask.getNewPriority(); break; } } pfields.put(DelugeCommon.convertPriority(newPriority, version)); } params.put(pfields); // keys // Make a single call to set the priorities on all files at once makeRequest(buildRequest(RPC_METHOD_SETFILE, params), log); return new DaemonTaskSuccessResult(task); case SetDownloadLocation: // Set the download location of some torrent SetDownloadLocationTask sdlTask = (SetDownloadLocationTask) task; // This works, but does not move the torrent //makeRequest(buildRequest(RPC_METHOD_SETOPTIONS, buildSetTorrentOptions( // sdlTask.getTargetTorrent().getUniqueID(), RPC_DOWNLOADLOCATION, sdlTask.getNewLocation()))); params.put(new JSONArray().put(task.getTargetTorrent().getUniqueID())); params.put(sdlTask.getNewLocation()); makeRequest(buildRequest(RPC_METHOD_MOVESTORAGE, params), log); return new DaemonTaskSuccessResult(task); case SetTransferRates: // Request to set the maximum transfer rates SetTransferRatesTask ratesTask = (SetTransferRatesTask) task; JSONObject map = new JSONObject(); map.put(RPC_MAXUPLOAD, (ratesTask.getUploadRate() == null ? -1 : ratesTask.getUploadRate())); map.put(RPC_MAXDOWNLOAD, (ratesTask.getDownloadRate() == null ? -1 : ratesTask.getDownloadRate())); makeRequest(buildRequest(RPC_METHOD_SETCONFIG, (new JSONArray()).put(map)), log); return new DaemonTaskSuccessResult(task); case SetLabel: // Request to set the label SetLabelTask labelTask = (SetLabelTask) task; params.put(task.getTargetTorrent().getUniqueID()); params.put(labelTask.getNewLabel() == null ? "" : labelTask.getNewLabel()); makeRequest(buildRequest(RPC_METHOD_SETLABEL, params), log); return new DaemonTaskSuccessResult(task); case SetTrackers: // Set the trackers of some torrent SetTrackersTask trackersTask = (SetTrackersTask) task; JSONArray trackers = new JSONArray(); // Build an JSON arrays of objcts that each have a tier (order) number and an url for (int i = 0; i < trackersTask.getNewTrackers().size(); i++) { JSONObject trackerObj = new JSONObject(); trackerObj.put(RPC_TIER, i); trackerObj.put(RPC_URL, trackersTask.getNewTrackers().get(i)); trackers.put(trackerObj); } params.put(new JSONArray().put(task.getTargetTorrent().getUniqueID())); params.put(trackers); makeRequest(buildRequest(RPC_METHOD_SETTRACKERS, params), log); return new DaemonTaskSuccessResult(task); case ForceRecheck: // Pause a torrent makeRequest(buildRequest(RPC_METHOD_FORCERECHECK, ((new JSONArray()).put((new JSONArray()).put(task.getTargetTorrent() .getUniqueID())))), log); return new DaemonTaskSuccessResult(task); default: return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.MethodUnsupported, task.getMethod() + " is not " + "supported by " + getType())); } } catch (JSONException e) { return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.ParsingFailed, e.toString())); } catch (DaemonException e) { return new DaemonTaskFailureResult(task, e); } catch (FileNotFoundException e) { return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, e.toString())); } catch (IOException e) { return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, e.toString())); } } /*private JSONArray buildSetTorrentOptions(String torrent, String key, String value) throws JSONException { JSONArray params = new JSONArray(); params.put(new JSONArray().put(torrent)); // torrent_id JSONObject sdlmap = new JSONObject(); // Set the option setting to the torrent sdlmap.put(key, value); params.put(sdlmap); // options return params; }*/ private void ensureVersion(Log log) throws DaemonException { if (version > 0) { return; } // We still need to retrieve the version number from the server // Do this by getting the web interface main html page and trying to parse the version number // Format is something like 'Deluge: Web UI 1.3.6' if (httpclient == null) { initialise(); } try { HttpResponse response = httpclient.execute(new HttpGet(buildWebUIUrl() + "/")); String main = HttpHelper.convertStreamToString(response.getEntity().getContent()); String titleStartText = "Deluge: Web UI "; String titleEndText = ""; int titleStart = main.indexOf(titleStartText); int titleEnd = main.indexOf(titleEndText, titleStart); if (titleStart >= 0 && titleEnd > titleStart) { // String found: now parse a version like 2.9.7 as a number like 20907 (allowing 10 places for each .) version = DelugeCommon.getVersionString(main.substring(titleStart + titleStartText.length(), titleEnd)); } } catch (NumberFormatException e) { log.d(LOG_NAME, "Error parsing the Deluge version code as number: " + e.toString()); // Continue though, ignoring the version number } catch (Exception e) { log.d(LOG_NAME, "Error: " + e.toString()); throw new DaemonException(ExceptionType.ConnectionError, e.toString()); } // Unable to establish version number; assume an old version by setting it to version 1 version = 10000; } private JSONObject buildRequest(String sendMethod, JSONArray params) throws JSONException { // Build request for method JSONObject request = new JSONObject(); request.put(RPC_METHOD, sendMethod); request.put(RPC_PARAMS, (params == null) ? new JSONArray() : params); request.put(RPC_ID, 2); return request; } private synchronized JSONObject makeRequest(JSONObject data, Log log) throws DaemonException { try { // Initialise the HTTP client if (httpclient == null) { initialise(); } // Login first? if (sessionCookie == null) { // Build login object String extraPass = settings.getExtraPassword(); if (extraPass == null) { extraPass = ""; } JSONObject loginRequest = new JSONObject(); loginRequest.put(RPC_METHOD, RPC_METHOD_AUTH_LOGIN); loginRequest.put(RPC_PARAMS, (new JSONArray()).put(extraPass)); loginRequest.put(RPC_ID, 1); // Set POST URL and data HttpPost httppost = new HttpPost(buildWebUIUrl() + PATH_TO_RPC); httppost.setHeader("content-type", "application/json"); StringEntity se = new StringEntity(loginRequest.toString()); httppost.setEntity(se); // Execute HttpResponse response = httpclient.execute(httppost); InputStream instream = response.getEntity().getContent(); // Retrieve session ID if (!httpclient.getCookieStore().getCookies().isEmpty()) { for (Cookie cookie : httpclient.getCookieStore().getCookies()) { if (cookie.getName().equals(RPC_SESSION_ID)) { sessionCookie = cookie; break; } } } // Still no session cookie? if (sessionCookie == null) { // Set error message and cancel the action that was requested throw new DaemonException(ExceptionType.AuthenticationFailure, "Password error? Server time difference? No (valid) cookie in " + "response and JSON was: " + HttpHelper.convertStreamToString(instream)); } } // Regular action // Set POST URL and data HttpPost httppost = new HttpPost(buildWebUIUrl() + PATH_TO_RPC); httppost.setHeader("content-type", "application/json"); StringEntity se = new StringEntity(data.toString(), HTTP.UTF_8); httppost.setEntity(se); // Set session cookie, if it was not in the httpclient object yet boolean cookiePresent = false; for (Cookie cookie : httpclient.getCookieStore().getCookies()) { if (cookie.getName().equals(RPC_SESSION_ID)) { cookiePresent = true; break; } } if (!cookiePresent) { httpclient.getCookieStore().addCookie(sessionCookie); } // Execute HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); if (entity != null) { // Read JSON response InputStream instream = entity.getContent(); String result = HttpHelper.convertStreamToString(instream); JSONObject json = new JSONObject(result); instream.close(); log.d(LOG_NAME, "Success: " + (result.length() > 300 ? result.substring(0, 300) + "... (" + result.length() + " chars)" : result)); // Return JSON object return json; } // No result? throw new DaemonException(ExceptionType.UnexpectedResponse, "No HTTP entity in response object."); } catch (JSONException e) { log.d(LOG_NAME, "Error: " + e.toString()); throw new DaemonException(ExceptionType.UnexpectedResponse, e.toString()); } catch (Exception e) { log.d(LOG_NAME, "Error: " + e.toString()); throw new DaemonException(ExceptionType.ConnectionError, e.toString()); } } /** * Instantiates an HTTP client with proper credentials that can be used for all Transmission requests. * @throws DaemonException On missing settings */ private void initialise() throws DaemonException { httpclient = HttpHelper.createStandardHttpClient(settings, settings.getUsername() != null && !settings.getUsername().equals("")); httpclient.addRequestInterceptor(HttpHelper.gzipRequestInterceptor); httpclient.addResponseInterceptor(HttpHelper.gzipResponseInterceptor); } /** * Build the URL of the Transmission web UI from the user settings. * @return The URL of the RPC API */ private String buildWebUIUrl() { return (settings.getSsl() ? "https://" : "http://") + settings.getAddress() + ":" + settings.getPort() + (settings.getFolder() == null ? "" : settings.getFolder()); } private ArrayList parseJsonRetrieveTorrents(JSONObject response) throws JSONException, DaemonException { // Parse response ArrayList torrents = new ArrayList<>(); if (response.isNull(RPC_TORRENTS)) { throw new DaemonException(ExceptionType.NotConnected, "Web interface probably not connected to a daemon yet, because 'torrents' is null:" + " " + response.toString()); } JSONObject objects = response.getJSONObject(RPC_TORRENTS); JSONArray names = objects.names(); if (names != null) { for (int j = 0; j < names.length(); j++) { JSONObject tor = objects.getJSONObject(names.getString(j)); // Add the parsed torrent to the list TorrentStatus status = DelugeCommon.convertDelugeState(tor.getString(RPC_STATUS)); String error = tor.getString(RPC_MESSAGE); if (tor.getString(RPC_TRACKER_STATUS).indexOf("Error") > 0) { error += (error.length() > 0 ? "\n" : "") + tor.getString(RPC_TRACKER_STATUS); //status = TorrentStatus.Error; // Don't report this as blocking error } // @formatter:off torrents.add(new Torrent(j, names.getString(j), tor.getString(RPC_NAME), status, tor.getString(RPC_SAVEPATH) + settings.getOS().getPathSeperator(), tor.getInt(RPC_RATEDOWNLOAD), tor.getInt(RPC_RATEUPLOAD), tor.getInt(RPC_NUMSEEDS), tor.getInt(RPC_TOTALSEEDS), tor.getInt(RPC_NUMPEERS), tor.getInt(RPC_TOTALPEERS), tor.getInt(RPC_ETA), tor.getLong(RPC_DOWNLOADEDEVER), tor.getLong(RPC_UPLOADEDEVER), tor.getLong(RPC_TOTALSIZE), ((float) tor.getDouble(RPC_PARTDONE)) / 100f, // Percentage to [0..1] 0f, // Not available tor.has(RPC_LABEL)? tor.getString(RPC_LABEL): null, tor.has(RPC_TIMEADDED)? new Date((long) (tor.getDouble(RPC_TIMEADDED) * 1000L)): null, null, // Not available error, settings.getType())); // @formatter:on } } // Return the list return torrents; } private ArrayList