From cd99cbb1597ce57fffa2af497af2e271ab0b2e8b Mon Sep 17 00:00:00 2001 From: Phillip Dykman Date: Wed, 27 Nov 2019 22:32:06 -0800 Subject: [PATCH] Add sequential download and first+last piece prioratization download modes, implemented for qbittorrent --- .../transdroid/core/gui/DetailsActivity.java | 26 ++++++++++++++++ .../transdroid/core/gui/DetailsFragment.java | 27 ++++++++++++++++ .../core/gui/TorrentTasksExecutor.java | 4 +++ .../transdroid/core/gui/TorrentsActivity.java | 26 ++++++++++++++++ .../java/org/transdroid/daemon/Daemon.java | 8 +++++ .../org/transdroid/daemon/DaemonMethod.java | 4 ++- .../Qbittorrent/QbittorrentAdapter.java | 31 +++++++++++++++---- .../java/org/transdroid/daemon/Torrent.java | 23 ++++++++++++++ .../ToggleFirstLastPieceDownloadTask.java | 31 +++++++++++++++++++ .../task/ToggleSequentialDownloadTask.java | 31 +++++++++++++++++++ app/src/main/res/menu/fragment_details.xml | 31 ++++++++++++++----- app/src/main/res/values/strings.xml | 4 +++ 12 files changed, 232 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/org/transdroid/daemon/task/ToggleFirstLastPieceDownloadTask.java create mode 100644 app/src/main/java/org/transdroid/daemon/task/ToggleSequentialDownloadTask.java diff --git a/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java b/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java index 8a0da758..205731a1 100644 --- a/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java +++ b/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java @@ -56,6 +56,8 @@ import org.transdroid.daemon.TorrentFile; import org.transdroid.daemon.task.DaemonTaskFailureResult; import org.transdroid.daemon.task.DaemonTaskResult; import org.transdroid.daemon.task.DaemonTaskSuccessResult; +import org.transdroid.daemon.task.ToggleSequentialDownloadTask; +import org.transdroid.daemon.task.ToggleFirstLastPieceDownloadTask; import org.transdroid.daemon.task.ForceRecheckTask; import org.transdroid.daemon.task.GetFileListTask; import org.transdroid.daemon.task.GetFileListTaskSuccessResult; @@ -278,6 +280,30 @@ public class DetailsActivity extends AppCompatActivity implements TorrentTasksEx } } + @Background + @Override + public void toggleSequentialDownload(Torrent torrent, boolean sequentialState) { + torrent.mimicSequentialDownload(sequentialState); + DaemonTaskResult result = ToggleSequentialDownloadTask.create(currentConnection, torrent).execute(log); + if (result instanceof DaemonTaskSuccessResult) { + onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_togglesequential)); + } else { + onCommunicationError((DaemonTaskFailureResult) result, false); + } + } + + @Background + @Override + public void toggleFirstLastPieceDownload(Torrent torrent, boolean firstLastPieceState) { + torrent.mimicFirstLastPieceDownload(firstLastPieceState); + DaemonTaskResult result = ToggleFirstLastPieceDownloadTask.create(currentConnection, torrent).execute(log); + if (result instanceof DaemonTaskSuccessResult) { + onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.action_toggle_firstlastpiece)); + } else { + onCommunicationError((DaemonTaskFailureResult) result, false); + } + } + @Background @Override public void forceRecheckTorrent(Torrent torrent) { diff --git a/app/src/main/java/org/transdroid/core/gui/DetailsFragment.java b/app/src/main/java/org/transdroid/core/gui/DetailsFragment.java index 79843c00..5648bee0 100644 --- a/app/src/main/java/org/transdroid/core/gui/DetailsFragment.java +++ b/app/src/main/java/org/transdroid/core/gui/DetailsFragment.java @@ -301,6 +301,12 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen case R.id.action_stop: stopTorrent(); return true; + case R.id.action_toggle_sequential: + toggleSequentialDownload(menuItem); + return true; + case R.id.action_toggle_firstlastpiece: + toggleFirstLastPieceDownload(menuItem); + return true; case R.id.action_forcerecheck: setForceRecheck(); return true; @@ -359,6 +365,15 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen detailsMenu.getMenu().findItem(R.id.action_setlabel).setVisible(setLabel); boolean forceRecheck = Daemon.supportsForceRecheck(torrent.getDaemon()); detailsMenu.getMenu().findItem(R.id.action_forcerecheck).setVisible(forceRecheck); + boolean sequentialdl = Daemon.supportsSequentialDownload(torrent.getDaemon()); + MenuItem seqMenuItem = detailsMenu.getMenu().findItem(R.id.action_toggle_sequential); + seqMenuItem.setVisible(sequentialdl); + seqMenuItem.setChecked(torrent.isSequentiallyDownloading()); + boolean firstlastpiecedl = Daemon.supportsFirstLastPiece(torrent.getDaemon()); + MenuItem flpMenuItem = detailsMenu.getMenu().findItem(R.id.action_toggle_firstlastpiece); + flpMenuItem.setVisible(firstlastpiecedl); + flpMenuItem.setChecked(torrent.isDownloadingFirstLastPieceFirst()); + detailsMenu.getMenu().findItem(R.id.action_download_mode).setVisible(firstlastpiecedl || sequentialdl); boolean setTrackers = Daemon.supportsSetTrackers(torrent.getDaemon()); detailsMenu.getMenu().findItem(R.id.action_updatetrackers).setVisible(setTrackers); boolean setLocation = Daemon.supportsSetDownloadLocation(torrent.getDaemon()); @@ -421,6 +436,18 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen } } + @OptionsItem(R.id.action_toggle_sequential) + protected void toggleSequentialDownload(MenuItem menuItem) { + if (getTasksExecutor() != null) + getTasksExecutor().toggleSequentialDownload(torrent, !menuItem.isChecked()); + } + + @OptionsItem(R.id.action_toggle_firstlastpiece) + protected void toggleFirstLastPieceDownload(MenuItem menuItem) { + if (getTasksExecutor() != null) + getTasksExecutor().toggleFirstLastPieceDownload(torrent, !menuItem.isChecked()); + } + @OptionsItem(R.id.action_forcerecheck) protected void setForceRecheck() { if (getTasksExecutor() != null) diff --git a/app/src/main/java/org/transdroid/core/gui/TorrentTasksExecutor.java b/app/src/main/java/org/transdroid/core/gui/TorrentTasksExecutor.java index b9418bb9..cb405ce2 100644 --- a/app/src/main/java/org/transdroid/core/gui/TorrentTasksExecutor.java +++ b/app/src/main/java/org/transdroid/core/gui/TorrentTasksExecutor.java @@ -40,6 +40,10 @@ public interface TorrentTasksExecutor { void removeTorrent(Torrent torrent, boolean withData); + void toggleSequentialDownload(Torrent torrent, boolean sequentialState); + + void toggleFirstLastPieceDownload(Torrent torrent, boolean sequentialState); + void forceRecheckTorrent(Torrent torrent); void updateLabel(Torrent torrent, String newLabel); diff --git a/app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java b/app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java index 2956cf2b..a0d259e2 100644 --- a/app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java +++ b/app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java @@ -103,6 +103,8 @@ import org.transdroid.daemon.task.AddByUrlTask; import org.transdroid.daemon.task.DaemonTaskFailureResult; import org.transdroid.daemon.task.DaemonTaskResult; import org.transdroid.daemon.task.DaemonTaskSuccessResult; +import org.transdroid.daemon.task.ToggleSequentialDownloadTask; +import org.transdroid.daemon.task.ToggleFirstLastPieceDownloadTask; import org.transdroid.daemon.task.ForceRecheckTask; import org.transdroid.daemon.task.GetFileListTask; import org.transdroid.daemon.task.GetFileListTaskSuccessResult; @@ -1225,6 +1227,30 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE } } + @Background + @Override + public void toggleSequentialDownload(Torrent torrent, boolean sequentialState) { + torrent.mimicSequentialDownload(sequentialState); + DaemonTaskResult result = ToggleSequentialDownloadTask.create(currentConnection, torrent).execute(log); + if (result instanceof DaemonTaskSuccessResult) { + onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_togglesequential)); + } else { + onCommunicationError((DaemonTaskFailureResult) result, false); + } + } + + @Background + @Override + public void toggleFirstLastPieceDownload(Torrent torrent, boolean firstLastPieceState) { + torrent.mimicFirstLastPieceDownload(firstLastPieceState); + DaemonTaskResult result = ToggleFirstLastPieceDownloadTask.create(currentConnection, torrent).execute(log); + if (result instanceof DaemonTaskSuccessResult) { + onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.action_toggle_firstlastpiece)); + } else { + onCommunicationError((DaemonTaskFailureResult) result, false); + } + } + @Background @Override public void forceRecheckTorrent(Torrent torrent) { diff --git a/app/src/main/java/org/transdroid/daemon/Daemon.java b/app/src/main/java/org/transdroid/daemon/Daemon.java index d4d88c5e..121f6674 100644 --- a/app/src/main/java/org/transdroid/daemon/Daemon.java +++ b/app/src/main/java/org/transdroid/daemon/Daemon.java @@ -412,6 +412,14 @@ public enum Daemon { || type == Transmission || type == Dummy || type == qBittorrent; } + public static boolean supportsSequentialDownload(Daemon type) { + return type == qBittorrent; + } + + public static boolean supportsFirstLastPiece(Daemon type) { + return type == qBittorrent; + } + public static boolean supportsExtraPassword(Daemon type) { return type == Deluge || type == Aria2; } diff --git a/app/src/main/java/org/transdroid/daemon/DaemonMethod.java b/app/src/main/java/org/transdroid/daemon/DaemonMethod.java index f9ec9b7b..e0e242ef 100644 --- a/app/src/main/java/org/transdroid/daemon/DaemonMethod.java +++ b/app/src/main/java/org/transdroid/daemon/DaemonMethod.java @@ -44,7 +44,9 @@ public enum DaemonMethod { SetTrackers (19), SetAlternativeMode (20), GetStats (21), - ForceRecheck (22); + ForceRecheck (22), + ToggleSequentialDownload(23), + ToggleFirstLastPieceDownload(24); private int code; private static final Map lookup = new HashMap<>(); diff --git a/app/src/main/java/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java b/app/src/main/java/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java index 0982053d..7f693b8f 100644 --- a/app/src/main/java/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java +++ b/app/src/main/java/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java @@ -286,11 +286,23 @@ public class QbittorrentAdapter implements IDaemonAdapter { } return new DaemonTaskSuccessResult(task); - case ForceRecheck: + case ForceRecheck: - // Force recheck a torrent - makeRequest(log, "/command/recheck", new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID())); - return new DaemonTaskSuccessResult(task); + // Force recheck a torrent + makeRequest(log, "/command/recheck", new BasicNameValuePair("hash", task.getTargetTorrent().getUniqueID())); + return new DaemonTaskSuccessResult(task); + + case ToggleSequentialDownload: + + // Toggle sequential download mode on a torrent + makeRequest(log, "/command/toggleSequentialDownload", new BasicNameValuePair("hashes", task.getTargetTorrent().getUniqueID())); + return new DaemonTaskSuccessResult(task); + + case ToggleFirstLastPieceDownload: + + // Set policy for downloading first and last piece first on a torrent + makeRequest(log, "/command/toggleFirstLastPiecePrio", new BasicNameValuePair("hashes", task.getTargetTorrent().getUniqueID())); + return new DaemonTaskSuccessResult(task); case SetLabel: @@ -492,6 +504,8 @@ public class QbittorrentAdapter implements IDaemonAdapter { long uploaded; int dlspeed; int upspeed; + boolean dlseq = false; + boolean dlflp = false; Date addedOn = null; Date completionOn = null; String label = null; @@ -507,6 +521,8 @@ public class QbittorrentAdapter implements IDaemonAdapter { ratio = tor.getDouble("ratio"); dlspeed = tor.getInt("dlspeed"); upspeed = tor.getInt("upspeed"); + dlseq = tor.getBoolean("seq_dl"); + dlflp = tor.getBoolean("f_l_piece_prio"); if (tor.has("uploaded")) { uploaded = tor.getLong("uploaded"); } else { @@ -535,7 +551,7 @@ public class QbittorrentAdapter implements IDaemonAdapter { eta = (long) (size - (size * progress)) / dlspeed; // Add the parsed torrent to the list // @formatter:off - torrents.add(new Torrent( + Torrent torrent = new Torrent( (long) i, tor.getString("hash"), tor.getString("name"), @@ -557,7 +573,10 @@ public class QbittorrentAdapter implements IDaemonAdapter { addedOn, completionOn, null, - settings.getType())); + settings.getType()); + torrent.mimicSequentialDownload(dlseq); + torrent.mimicFirstLastPieceDownload(dlflp); + torrents.add(torrent); // @formatter:on } diff --git a/app/src/main/java/org/transdroid/daemon/Torrent.java b/app/src/main/java/org/transdroid/daemon/Torrent.java index 446b9022..b7dd249e 100644 --- a/app/src/main/java/org/transdroid/daemon/Torrent.java +++ b/app/src/main/java/org/transdroid/daemon/Torrent.java @@ -49,6 +49,8 @@ public final class Torrent implements Parcelable, Comparable, Finishabl final private float partDone; final private float available; private String label; + private boolean sequentialDownload; + private boolean firstLastPieceDownload; final private Date dateAdded; final private Date dateDone; @@ -76,6 +78,8 @@ public final class Torrent implements Parcelable, Comparable, Finishabl this.partDone = in.readFloat(); this.available = in.readFloat(); this.label = in.readString(); + this.sequentialDownload = in.readByte() != 0; + this.firstLastPieceDownload = in.readByte() != 0; long lDateAdded = in.readLong(); this.dateAdded = (lDateAdded == -1) ? null : new Date(lDateAdded); @@ -109,6 +113,8 @@ public final class Torrent implements Parcelable, Comparable, Finishabl this.partDone = partDone; this.available = available; this.label = label; + this.sequentialDownload = false; + this.firstLastPieceDownload = false; this.dateAdded = dateAdded; if (realDateDone != null) { @@ -197,6 +203,13 @@ public final class Torrent implements Parcelable, Comparable, Finishabl return label; } + public boolean isSequentiallyDownloading() { + return sequentialDownload; + } + public boolean isDownloadingFirstLastPieceFirst() { + return firstLastPieceDownload; + } + public Date getDateAdded() { return dateAdded; } @@ -342,6 +355,14 @@ public final class Torrent implements Parcelable, Comparable, Finishabl label = newLabel; } + public void mimicSequentialDownload(boolean sequentialDownload) { + this.sequentialDownload = sequentialDownload; + } + + public void mimicFirstLastPieceDownload(boolean firstLastPieceDownload) { + this.firstLastPieceDownload = firstLastPieceDownload; + } + public void mimicCheckingStatus() { statusCode = TorrentStatus.Checking; } @@ -399,6 +420,8 @@ public final class Torrent implements Parcelable, Comparable, Finishabl dest.writeFloat(partDone); dest.writeFloat(available); dest.writeString(label); + dest.writeByte((byte) (sequentialDownload ? 1 : 0)); + dest.writeByte((byte) (firstLastPieceDownload ? 1 : 0)); dest.writeLong((dateAdded == null) ? -1 : dateAdded.getTime()); dest.writeLong((dateDone == null) ? -1 : dateDone.getTime()); diff --git a/app/src/main/java/org/transdroid/daemon/task/ToggleFirstLastPieceDownloadTask.java b/app/src/main/java/org/transdroid/daemon/task/ToggleFirstLastPieceDownloadTask.java new file mode 100644 index 00000000..3030c325 --- /dev/null +++ b/app/src/main/java/org/transdroid/daemon/task/ToggleFirstLastPieceDownloadTask.java @@ -0,0 +1,31 @@ +/* + * 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.task; + +import org.transdroid.daemon.DaemonMethod; +import org.transdroid.daemon.IDaemonAdapter; +import org.transdroid.daemon.Torrent; + +public class ToggleFirstLastPieceDownloadTask extends DaemonTask { + protected ToggleFirstLastPieceDownloadTask(IDaemonAdapter adapter, Torrent targetTorrent) { + super(adapter, DaemonMethod.ToggleFirstLastPieceDownload, targetTorrent, null); + } + public static ToggleFirstLastPieceDownloadTask create(IDaemonAdapter adapter, Torrent targetTorrent) { + return new ToggleFirstLastPieceDownloadTask(adapter, targetTorrent); + } +} diff --git a/app/src/main/java/org/transdroid/daemon/task/ToggleSequentialDownloadTask.java b/app/src/main/java/org/transdroid/daemon/task/ToggleSequentialDownloadTask.java new file mode 100644 index 00000000..74575e14 --- /dev/null +++ b/app/src/main/java/org/transdroid/daemon/task/ToggleSequentialDownloadTask.java @@ -0,0 +1,31 @@ +/* + * 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.task; + +import org.transdroid.daemon.DaemonMethod; +import org.transdroid.daemon.IDaemonAdapter; +import org.transdroid.daemon.Torrent; + +public class ToggleSequentialDownloadTask extends DaemonTask { + protected ToggleSequentialDownloadTask(IDaemonAdapter adapter, Torrent targetTorrent) { + super(adapter, DaemonMethod.ToggleSequentialDownload, targetTorrent, null); + } + public static ToggleSequentialDownloadTask create(IDaemonAdapter adapter, Torrent targetTorrent) { + return new ToggleSequentialDownloadTask(adapter, targetTorrent); + } +} diff --git a/app/src/main/res/menu/fragment_details.xml b/app/src/main/res/menu/fragment_details.xml index 93a73257..7abfd206 100644 --- a/app/src/main/res/menu/fragment_details.xml +++ b/app/src/main/res/menu/fragment_details.xml @@ -47,19 +47,36 @@ + + + + + + @@ -74,25 +91,25 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7eb5dc56..c96932b3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,6 +56,9 @@ Remove torrent Remove and delete data Set label + Set download mode + Download sequentially + Download first and last pieces first Update trackers Change storage location Force data recheck @@ -175,6 +178,7 @@ Trackers updated Label set to \'%1$s\' Label removed + Toggled sequential download mode Checking %1$s data Torrent moved to \'%1$s\' File priorities updated