Browse Source

Merge pull request #422 from alonalbert/deluge-rss

Deluge Remote RSS
pull/424/head
Eric Kok 6 years ago committed by GitHub
parent
commit
48d2b1a63b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java
  2. 138
      app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssActivity.java
  3. 89
      app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssFragment.java
  4. 9
      app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssSupplier.java
  5. 2
      app/src/main/java/org/transdroid/daemon/Daemon.java
  6. 8
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeCommon.java
  7. 85
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRemoteRssChannel.java
  8. 47
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRemoteRssItem.java
  9. 123
      app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcAdapter.java
  10. 14
      app/src/main/java/org/transdroid/daemon/Utorrent/UtorrentAdapter.java
  11. 23
      app/src/main/res/layout/fragment_remoterss.xml
  12. 1
      app/src/main/res/values/strings.xml

17
app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java

@ -84,8 +84,6 @@ import org.transdroid.core.gui.navigation.NavigationHelper; @@ -84,8 +84,6 @@ import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.gui.navigation.RefreshableActivity;
import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.core.gui.remoterss.RemoteRssActivity_;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.core.gui.rss.RssfeedsActivity_;
import org.transdroid.core.gui.search.BarcodeHelper;
import org.transdroid.core.gui.search.FilePickerHelper;
@ -854,18 +852,11 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE @@ -854,18 +852,11 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE
}
@OptionsItem(R.id.action_remoterss)
@Background
protected void openRemoteRss() {
ArrayList<RemoteRssChannel> rssFeedItems = ((RemoteRssSupplier) (currentConnection)).getRemoteRssChannels();
if (rssFeedItems.size() == 0) {
return;
}
// Passing the items over as a feed can overload the Intent size limit and crash without a stack trace!
RemoteRssActivity_.intent(this)
// .feeds(rssFeedItems)
.start()
;
// Passing the items over as a feed can overload the Intent size limit and crash without a stack trace.
// Loading the items can take a while so we don't want to load them here and again in the RemoteRssActivity.
RemoteRssActivity_.intent(this).start();
}
@OptionsItem(R.id.action_help)

138
app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssActivity.java

@ -26,23 +26,34 @@ import android.support.v7.widget.Toolbar; @@ -26,23 +26,34 @@ import android.support.v7.widget.Toolbar;
import android.widget.LinearLayout;
import android.widget.ListView;
import com.nispok.snackbar.Snackbar;
import com.nispok.snackbar.SnackbarManager;
import com.nispok.snackbar.enums.SnackbarType;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.FragmentById;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.NonConfigurationInstance;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.lists.LocalTorrent;
import org.transdroid.core.gui.lists.SimpleListItemAdapter;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.navigation.RefreshableActivity;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.IDaemonAdapter;
import java.util.ArrayList;
@ -61,18 +72,22 @@ import java.util.List; @@ -61,18 +72,22 @@ import java.util.List;
* @author Twig Nguyen
*/
@EActivity(R.layout.activity_remoterss)
public class RemoteRssActivity extends AppCompatActivity {
// @Extra
@InstanceState
public class RemoteRssActivity extends AppCompatActivity implements RefreshableActivity {
@NonConfigurationInstance
protected ArrayList<RemoteRssChannel> feeds;
@InstanceState
protected int selectedFilter;
@NonConfigurationInstance
protected ArrayList<RemoteRssItem> recentItems;
// Server connection
@Bean
protected ApplicationSettings applicationSettings;
@Bean
protected Log log;
@Bean
protected ConnectivityHelper connectivityHelper;
private IDaemonAdapter currentConnection;
@ -110,13 +125,67 @@ public class RemoteRssActivity extends AppCompatActivity { @@ -110,13 +125,67 @@ public class RemoteRssActivity extends AppCompatActivity {
// Connect to the last used server
ServerSetting lastUsed = applicationSettings.getLastUsedServer();
currentConnection = lastUsed.createServerAdapter(connectivityHelper.getConnectedNetworkName(), this);
feeds = ((RemoteRssSupplier) (currentConnection)).getRemoteRssChannels();
// Fill in the filter list
if (feeds != null) {
// Called from a configuration change. No need to load anything from server
showChannelFilters();
fragmentRemoteRss.updateRemoteItems(
selectedFilter == 0 ? recentItems : feeds.get(selectedFilter - 1).getItems(),
false /* allow android to restore scroll position */ );
} else {
loadFeeds();
}
}
@Background
protected void loadFeeds() {
try {
fragmentRemoteRss.setRefreshing(true);
feeds = ((RemoteRssSupplier) (currentConnection)).getRemoteRssChannels(log);
fragmentRemoteRss.setRefreshing(false);
} catch (DaemonException e) {
onCommunicationError(e);
}
recentItems = new ArrayList<>();
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -1);
Date oneMonthAgo = calendar.getTime();
for (RemoteRssChannel feed : feeds) {
for (RemoteRssItem item : feed.getItems()) {
if (item.getTimestamp().after(oneMonthAgo)) {
recentItems.add(item);
}
}
}
// Sort by -newest
Collections.sort(recentItems, new Comparator<RemoteRssItem>() {
@Override
public int compare(RemoteRssItem lhs, RemoteRssItem rhs) {
return rhs.getTimestamp().compareTo(lhs.getTimestamp());
}
});
afterLoadFeeds();
}
@UiThread
protected void afterLoadFeeds() {
// We need to wrap these calls in a @UiThread rather than make them each a @UiThread themselves
// because they need to run sequentially in a configuration change scenario in order for Android
// to maintain scroll position on the fragment adapter.
showChannelFilters();
onFeedSelected(selectedFilter);
}
// Show all items
showRecentItems();
@UiThread
protected void onCommunicationError(DaemonException daemonException) {
//noinspection ThrowableResultOfMethodCallIgnored
log.i(this, daemonException.toString());
String error = getString(LocalTorrent.getResourceForDaemonException(daemonException));
SnackbarManager.show(Snackbar.with(this).text(error).colorResource(R.color.red).type(SnackbarType.MULTI_LINE));
}
@ -139,36 +208,7 @@ public class RemoteRssActivity extends AppCompatActivity { @@ -139,36 +208,7 @@ public class RemoteRssActivity extends AppCompatActivity {
}
}
protected void showRecentItems() {
if (recentItems == null) {
recentItems = new ArrayList<>();
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -1);
Date oneMonthAgo = calendar.getTime();
for (RemoteRssChannel feed : feeds) {
for (RemoteRssItem item : feed.getItems()) {
if (item.getTimestamp().after(oneMonthAgo)) {
recentItems.add(item);
}
}
}
// Sort by -newest
Collections.sort(recentItems, new Comparator<RemoteRssItem>() {
@Override
public int compare(RemoteRssItem lhs, RemoteRssItem rhs) {
return rhs.getTimestamp().compareTo(lhs.getTimestamp());
}
});
}
fragmentRemoteRss.updateRemoteItems(recentItems);
RemoteRssChannel channel = (RemoteRssChannel) drawerList.getAdapter().getItem(0);
getSupportActionBar().setSubtitle(channel.getName());
}
protected void showChannelFilters() {
private void showChannelFilters() {
List<RemoteRssChannel> feedLabels = new ArrayList<>(feeds.size() +1);
feedLabels.add(new RemoteRssChannel() {
@Override
@ -187,12 +227,8 @@ public class RemoteRssActivity extends AppCompatActivity { @@ -187,12 +227,8 @@ public class RemoteRssActivity extends AppCompatActivity {
@ItemClick(R.id.drawer_list)
protected void onFeedSelected(int position) {
if (position == 0) {
showRecentItems();
}
else {
fragmentRemoteRss.updateRemoteItems(feeds.get(position -1).getItems());
}
selectedFilter = position;
fragmentRemoteRss.updateRemoteItems(position == 0 ? recentItems : feeds.get(position - 1).getItems(), true);
RemoteRssChannel channel = (RemoteRssChannel) drawerList.getAdapter().getItem(position);
getSupportActionBar().setSubtitle(channel.getName());
@ -203,4 +239,18 @@ public class RemoteRssActivity extends AppCompatActivity { @@ -203,4 +239,18 @@ public class RemoteRssActivity extends AppCompatActivity {
public IDaemonAdapter getCurrentConnection() {
return currentConnection;
}
}
public RemoteRssChannel getChannel(String name) {
for (RemoteRssChannel feed : feeds) {
if (feed.getName().equals(name)) {
return feed;
}
}
return null;
}
@Override
public void refreshScreen() {
loadFeeds();
}
}

89
app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssFragment.java

@ -32,20 +32,16 @@ import org.androidannotations.annotations.AfterViews; @@ -32,20 +32,16 @@ import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.lists.LocalTorrent;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.navigation.RefreshableActivity;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.task.AddByMagnetUrlTask;
import org.transdroid.daemon.task.AddByUrlTask;
import org.transdroid.daemon.task.DaemonTaskFailureResult;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.task.DaemonTaskSuccessResult;
import java.util.ArrayList;
@ -62,7 +58,6 @@ public class RemoteRssFragment extends Fragment { @@ -62,7 +58,6 @@ public class RemoteRssFragment extends Fragment {
protected Log log;
// Local data
@InstanceState
protected ArrayList<RemoteRssItem> remoteRssItems;
// Views
@ -75,7 +70,7 @@ public class RemoteRssFragment extends Fragment { @@ -75,7 +70,7 @@ public class RemoteRssFragment extends Fragment {
@ViewById
protected ListView torrentsList;
@ViewById
protected TextView remoterssNoFilesMessage;
protected TextView remoterssStatusMessage;
protected RemoteRssItemsAdapter adapter;
@ -100,27 +95,45 @@ public class RemoteRssFragment extends Fragment { @@ -100,27 +95,45 @@ public class RemoteRssFragment extends Fragment {
torrentsList.setAdapter(adapter);
torrentsList.setFastScrollEnabled(true);
// Restore the fragment state (on orientation changes et al.)
if (remoteRssItems != null) {
updateRemoteItems(remoteRssItems);
// Allow pulls on the list view to refresh the torrents
if (getActivity() != null && getActivity() instanceof RefreshableActivity) {
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
((RefreshableActivity) getActivity()).refreshScreen();
}
});
}
}
/**
* Updates the UI with a new list of RSS items.
*/
public void updateRemoteItems(List<RemoteRssItem> remoteItems) {
public void updateRemoteItems(List<RemoteRssItem> remoteItems, boolean scrollToTop) {
remoteRssItems = new ArrayList<>(remoteItems);
adapter.updateItems(remoteRssItems);
torrentsList.smoothScrollToPosition(0);
if (scrollToTop) {
torrentsList.smoothScrollToPosition(0);
}
// Show/hide a nice message if there are no items to show
remoterssNoFilesMessage.setVisibility(remoteRssItems.size() > 0 ? View.GONE : View.VISIBLE);
if (remoteRssItems.size() > 0) {
remoterssStatusMessage.setVisibility(View.GONE);
}
else {
remoterssStatusMessage.setVisibility(View.VISIBLE);
remoterssStatusMessage.setText(R.string.remoterss_no_files);
}
swipeRefreshLayout.setRefreshing(false);
}
@UiThread
public void setRefreshing(boolean refreshing) {
swipeRefreshLayout.setRefreshing(refreshing);
}
/**
* When the user clicks on an item, prepare to download it.
*/
*/
@ItemClick(resName = "torrents_list")
protected void detailsListClicked(int position) {
RemoteRssItem item = (RemoteRssItem) adapter.getItem(position);
@ -129,33 +142,17 @@ public class RemoteRssFragment extends Fragment { @@ -129,33 +142,17 @@ public class RemoteRssFragment extends Fragment {
/**
* Download the item in a background thread and display success/fail accordingly.
*/
*/
@Background
protected void downloadRemoteRssItem(RemoteRssItem item) {
RemoteRssActivity activity = (RemoteRssActivity) getActivity();
IDaemonAdapter currentConnection = activity.getCurrentConnection();
DaemonTaskResult result;
if (item.isMagnetLink()) {
// Check if it's supported
if (!Daemon.supportsAddByMagnetUrl(currentConnection.getType())) {
onTaskFailed(getString(R.string.error_magnet_links_unsupported));
return;
}
AddByMagnetUrlTask addByMagnetUrlTask = AddByMagnetUrlTask.create(currentConnection, item.getLink());
result = addByMagnetUrlTask.execute(log);
}
else {
result = AddByUrlTask.create(currentConnection, item.getLink(), item.getTitle()).execute(log);
}
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_added, item.getTitle()));
} else if (result instanceof DaemonTaskFailureResult){
DaemonTaskFailureResult failure = ((DaemonTaskFailureResult) result);
String message = getString(LocalTorrent.getResourceForDaemonException(failure.getException()));
onTaskFailed(message);
final RemoteRssActivity activity = (RemoteRssActivity) getActivity();
final RemoteRssSupplier supplier = (RemoteRssSupplier) activity.getCurrentConnection();
try {
supplier.downloadRemoteRssItem(log, item, activity.getChannel(item.getSourceName()));
onTaskSucceeded(null, getString(R.string.result_added, item.getTitle()));
} catch (DaemonException e) {
onTaskFailed(getString(LocalTorrent.getResourceForDaemonException(e)));
}
}
@ -167,9 +164,9 @@ public class RemoteRssFragment extends Fragment { @@ -167,9 +164,9 @@ public class RemoteRssFragment extends Fragment {
@UiThread
protected void onTaskFailed(String message) {
SnackbarManager.show(Snackbar.with(getActivity())
.text(message)
.colorResource(R.color.red)
.type(SnackbarType.MULTI_LINE)
.text(message)
.colorResource(R.color.red)
.type(SnackbarType.MULTI_LINE)
);
}
}
}

9
app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssSupplier.java

@ -1,5 +1,8 @@ @@ -1,5 +1,8 @@
package org.transdroid.core.gui.remoterss.data;
import org.transdroid.core.gui.log.Log;
import org.transdroid.daemon.DaemonException;
import java.util.ArrayList;
/**
@ -8,5 +11,7 @@ import java.util.ArrayList; @@ -8,5 +11,7 @@ import java.util.ArrayList;
* @author Twig
*/
public interface RemoteRssSupplier {
ArrayList<RemoteRssChannel> getRemoteRssChannels();
}
ArrayList<RemoteRssChannel> getRemoteRssChannels(Log log) throws DaemonException;
void downloadRemoteRssItem(Log log, RemoteRssItem rssItem, RemoteRssChannel rssChannel) throws DaemonException;
}

2
app/src/main/java/org/transdroid/daemon/Daemon.java

@ -401,6 +401,6 @@ public enum Daemon { @@ -401,6 +401,6 @@ public enum Daemon {
}
public static boolean supportsRemoteRssManagement(Daemon type) {
return type == uTorrent;
return type == uTorrent || type == DelugeRpc;
}
}

8
app/src/main/java/org/transdroid/daemon/Deluge/DelugeCommon.java

@ -29,6 +29,7 @@ import org.transdroid.daemon.TorrentStatus; @@ -29,6 +29,7 @@ import org.transdroid.daemon.TorrentStatus;
class DelugeCommon {
static final String RPC_DETAILS = "files";
static final String RPC_DOWNLOAD_LOCATION = "download_location";
static final String RPC_DOWNLOADEDEVER = "total_done";
static final String RPC_ETA = "eta";
static final String RPC_FILE = "file";
@ -37,6 +38,7 @@ class DelugeCommon { @@ -37,6 +38,7 @@ class DelugeCommon {
static final String RPC_HASH = "hash";
static final String RPC_INDEX = "index";
static final String RPC_LABEL = "label";
static final String RPC_KEY = "key";
static final String RPC_MAXDOWNLOAD = "max_download_speed";
static final String RPC_MAXUPLOAD = "max_upload_speed";
static final String RPC_MESSAGE = "message";
@ -64,6 +66,9 @@ class DelugeCommon { @@ -64,6 +66,9 @@ class DelugeCommon {
static final String RPC_METHOD_SETTRACKERS = "core.set_torrent_trackers";
static final String RPC_METHOD_SET_TORRENT_OPTIONS = "core.set_torrent_options";
static final String RPC_METHOD_STATUS = "core.get_torrent_status";
static final String RPC_METHOD_GET_RSS_CONFIG = "yarss2.get_config";
static final String RPC_MOVE_COMPLETED = "move_completed";
static final String RPC_MOVE_COMPLETED_PATH = "move_completed_path";
static final String RPC_NAME = "name";
static final String RPC_NUMPEERS = "num_peers";
static final String RPC_NUMSEEDS = "num_seeds";
@ -73,10 +78,13 @@ class DelugeCommon { @@ -73,10 +78,13 @@ class DelugeCommon {
static final String RPC_RATEDOWNLOAD = "download_payload_rate";
static final String RPC_RATEUPLOAD = "upload_payload_rate";
static final String RPC_RESULT = "result";
static final String RPC_RSSFEED_KEY = "rssfeed_key";
static final String RPC_RSSFEEDS = "rssfeeds";
static final String RPC_SAVEPATH = "save_path";
static final String RPC_SESSION_ID = "_session_id";
static final String RPC_SIZE = "size";
static final String RPC_STATUS = "state";
static final String RPC_SUBSCRIPTIONS = "subscriptions";
static final String RPC_TIMEADDED = "time_added";
static final String RPC_TORRENTS = "torrents";
static final String RPC_TOTALPEERS = "total_peers";

85
app/src/main/java/org/transdroid/daemon/Deluge/DelugeRemoteRssChannel.java

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
package org.transdroid.daemon.Deluge;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
/**
* Deluge implementation of RemoteRssChannel.
*
* @author alonalbert
*/
class DelugeRemoteRssChannel extends RemoteRssChannel {
private final String label;
private final String downloadLocation;
private final String moveCompleted;
DelugeRemoteRssChannel(
int id,
String name,
String link,
long lastUpdated,
String label, String downloadLocation, String moveCompleted, List<RemoteRssItem> items) {
this.label = label;
this.downloadLocation = downloadLocation;
this.moveCompleted = moveCompleted;
this.id = id;
this.name = name;
this.link = link;
this.lastUpdated = lastUpdated;
this.items = items;
}
private DelugeRemoteRssChannel(Parcel in) {
id = in.readInt();
name = in.readString();
link = in.readString();
lastUpdated = in.readLong();
label = in.readString();
downloadLocation = in.readString();
moveCompleted = in.readString();
items = new ArrayList<>();
in.readList(items, DelugeRemoteRssItem.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(link);
dest.writeLong(lastUpdated);
dest.writeString(label);
dest.writeString(downloadLocation);
dest.writeString(moveCompleted);
dest.writeList(items);
}
public String getLabel() {
return label;
}
public String getDownloadLocation() {
return downloadLocation;
}
public String getMoveCompleted() {
return moveCompleted;
}
public static final Parcelable.Creator<DelugeRemoteRssChannel> CREATOR = new Parcelable.Creator<DelugeRemoteRssChannel>() {
public DelugeRemoteRssChannel createFromParcel(Parcel in) {
return new DelugeRemoteRssChannel(in);
}
public DelugeRemoteRssChannel[] newArray(int size) {
return new DelugeRemoteRssChannel[size];
}
};
}

47
app/src/main/java/org/transdroid/daemon/Deluge/DelugeRemoteRssItem.java

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
package org.transdroid.daemon.Deluge;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Date;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
/**
* Deluge implementation of RemoteRssItem.
*
* @author alonalbert
*/
class DelugeRemoteRssItem extends RemoteRssItem {
DelugeRemoteRssItem(String title, String link, String sourceName, Date timestamp) {
this.title = title;
this.link = link;
this.sourceName = sourceName;
this.timestamp = timestamp;
}
private DelugeRemoteRssItem(Parcel in) {
title = in.readString();
link = in.readString();
sourceName = in.readString();
timestamp = (Date) in.readSerializable();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(title);
dest.writeString(link);
dest.writeString(sourceName);
dest.writeSerializable(timestamp);
}
public static final Parcelable.Creator<DelugeRemoteRssItem> CREATOR = new Parcelable.Creator<DelugeRemoteRssItem>() {
public DelugeRemoteRssItem createFromParcel(Parcel in) {
return new DelugeRemoteRssItem(in);
}
public DelugeRemoteRssItem[] newArray(int size) {
return new DelugeRemoteRssItem[size];
}
};
}

123
app/src/main/java/org/transdroid/daemon/Deluge/DelugeRpcAdapter.java

@ -21,6 +21,12 @@ import android.support.annotation.NonNull; @@ -21,6 +21,12 @@ import android.support.annotation.NonNull;
import org.base64.android.Base64;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.Item;
import org.transdroid.core.rssparser.RssParser;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
@ -51,6 +57,7 @@ import org.transdroid.daemon.task.SetFilePriorityTask; @@ -51,6 +57,7 @@ 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.xml.sax.SAXException;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
@ -70,9 +77,12 @@ import java.util.Map; @@ -70,9 +77,12 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
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_DOWNLOAD_LOCATION;
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_FILEPRIORITIES;
@ -80,6 +90,7 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_FILEPROGRESS; @@ -80,6 +90,7 @@ 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_HASH;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_INDEX;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_KEY;
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;
@ -90,6 +101,7 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD_MAGNET; @@ -90,6 +101,7 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_ADD_MAGNET;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_FORCERECHECK;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_LABELS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_METHOD_LIST;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_RSS_CONFIG;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_GET_TORRENTS_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_INFO;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_MOVESTORAGE;
@ -103,6 +115,8 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_SETLABEL; @@ -103,6 +115,8 @@ 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_SET_TORRENT_OPTIONS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_METHOD_STATUS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MOVE_COMPLETED;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_MOVE_COMPLETED_PATH;
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;
@ -110,9 +124,12 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_PARTDONE; @@ -110,9 +124,12 @@ 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_RSSFEEDS;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_RSSFEED_KEY;
import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_SAVEPATH;
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_SUBSCRIPTIONS;
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_TOTALPEERS;
@ -127,7 +144,7 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL; @@ -127,7 +144,7 @@ import static org.transdroid.daemon.Deluge.DelugeCommon.RPC_URL;
* The daemon adapter from the Deluge torrent client using deluged API directly.
* @author alon.albert
*/
public class DelugeRpcAdapter implements IDaemonAdapter {
public class DelugeRpcAdapter implements IDaemonAdapter, RemoteRssSupplier {
public static final int DEFAULT_PORT = 58846;
@ -200,6 +217,93 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -200,6 +217,93 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
return settings;
}
@Override
public ArrayList<RemoteRssChannel> getRemoteRssChannels(Log log) throws DaemonException {
final long now = System.currentTimeMillis();
final DelugeRpcClient client = new DelugeRpcClient();
try {
client.connect(settings);
if (!hasMethod(client, RPC_METHOD_GET_RSS_CONFIG)) {
throw new DaemonException(ExceptionType.MethodUnsupported, "YaRRS2 plugin not installed");
}
//noinspection unchecked
final Map<String, Object> rssConfig = (Map<String, Object>) client.sendRequest(RPC_METHOD_GET_RSS_CONFIG);
//noinspection unchecked
final Map<String, Map<String, Object>> rssFeeds = (Map<String, Map<String, Object>>) rssConfig.get(RPC_RSSFEEDS);
final Map<Object, String> feedUrlMap = new HashMap<>();
final Map<Object, List<Item>> feedItemMap = new HashMap<>();
for (Map<String, Object> feed : rssFeeds.values()) {
final String feedUrl = (String) feed.get(RPC_URL);
final Object key = feed.get(RPC_KEY);
feedUrlMap.put(key, feedUrl);
final List<Item> items = getRssFeedItems(feedUrl, log);
feedItemMap.put(key, items);
}
//noinspection unchecked
final Map<String, Map<String, Object>> subscriptions = (Map<String, Map<String, Object>>) rssConfig.get(RPC_SUBSCRIPTIONS);
final ArrayList<RemoteRssChannel> channels = new ArrayList<>();
for (Map<String, Object> subscription : subscriptions.values()) {
final Integer key = Integer.valueOf(subscription.get(RPC_KEY).toString());
final String name = (String) subscription.get(RPC_NAME);
final String label = (String) subscription.get(RPC_LABEL);
final String downloadLocation = (String) subscription.get(RPC_DOWNLOAD_LOCATION);
final String moveCompleted = (String) subscription.get(RPC_MOVE_COMPLETED);
final Object feedKey = subscription.get(RPC_RSSFEED_KEY);
final String feedUrl = feedUrlMap.get(feedKey);
final List<RemoteRssItem> items = new ArrayList<>();
for (Item item : feedItemMap.get(feedKey)) {
items.add(new DelugeRemoteRssItem(item.getTitle(), item.getLink(), name, item.getPubdate()));
}
channels.add(new DelugeRemoteRssChannel(key, name, feedUrl, now, label, downloadLocation, moveCompleted, items));
}
return channels;
} finally {
client.close();
android.util.Log.i("Alon", String.format("getRemoteRssChannels: %dms", System.currentTimeMillis() - now));
}
}
@Override
public void downloadRemoteRssItem(Log log, RemoteRssItem rssItem, RemoteRssChannel rssChannel) throws DaemonException {
final DelugeRemoteRssItem item = (DelugeRemoteRssItem) rssItem;
final DelugeRemoteRssChannel channel = (DelugeRemoteRssChannel) rssChannel;
final Map<String, Object> options = new HashMap<>();
final String label;
if (channel != null) {
final String downloadLocation = channel.getDownloadLocation();
if (downloadLocation != null) {
options.put(RPC_DOWNLOAD_LOCATION, downloadLocation);
}
final String moveCompleted = channel.getMoveCompleted();
if (moveCompleted != null) {
options.put(RPC_MOVE_COMPLETED, true);
options.put(RPC_MOVE_COMPLETED_PATH, moveCompleted);
}
label = channel.getLabel();
} else {
label = null;
}
final DelugeRpcClient client = new DelugeRpcClient();
try {
client.connect(settings);
final String torrentId = (String) client
.sendRequest(item.isMagnetLink() ? RPC_METHOD_ADD_MAGNET : RPC_METHOD_ADD, item.getLink(), options);
if (label != null && hasMethod(client, RPC_METHOD_SETLABEL)) {
client.sendRequest(RPC_METHOD_SETLABEL, torrentId, label);
}
} finally {
client.close();
}
}
@NonNull
private RetrieveTaskSuccessResult doRetrieve(DelugeRpcClient client, RetrieveTask task) throws DaemonException {
// Get torrents
@ -498,6 +602,23 @@ public class DelugeRpcAdapter implements IDaemonAdapter { @@ -498,6 +602,23 @@ public class DelugeRpcAdapter implements IDaemonAdapter {
return new String[]{task.getTargetTorrent().getUniqueID()};
}
@NonNull
private List<Item> getRssFeedItems(String feedUrl, Log log) {
final RssParser rssParser = new RssParser(feedUrl, null, null);
try {
rssParser.parse();
final Channel channel = rssParser.getChannel();
return channel.getItems();
} catch (ParserConfigurationException e) {
log.e(DelugeRpcAdapter.this, "Failed to parse RSS feed.");
} catch (SAXException e) {
log.e(DelugeRpcAdapter.this, "Failed to parse RSS feed.");
} catch (IOException e) {
log.e(DelugeRpcAdapter.this, "Failed to load RSS feed.");
}
return new ArrayList<>();
}
private boolean hasMethod(DelugeRpcClient client, String method) throws DaemonException {
//noinspection unchecked
final List<String> methods = (List<String>) client.sendRequest(RPC_METHOD_GET_METHOD_LIST);

14
app/src/main/java/org/transdroid/daemon/Utorrent/UtorrentAdapter.java

@ -30,6 +30,7 @@ import org.json.JSONException; @@ -30,6 +30,7 @@ import org.json.JSONException;
import org.json.JSONObject;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
@ -657,7 +658,18 @@ public class UtorrentAdapter implements IDaemonAdapter, RemoteRssSupplier { @@ -657,7 +658,18 @@ public class UtorrentAdapter implements IDaemonAdapter, RemoteRssSupplier {
return this.settings;
}
public ArrayList<RemoteRssChannel> getRemoteRssChannels() {
public ArrayList<RemoteRssChannel> getRemoteRssChannels(Log log) {
return remoteRssChannels;
}
@Override
public void downloadRemoteRssItem(Log log, RemoteRssItem rssItem, RemoteRssChannel rssChannel) throws DaemonException {
final String link = rssItem.getLink();
try {
makeUtorrentRequest(log, "&action=add-url&s=" + URLEncoder.encode(link, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new DaemonException(ExceptionType.ParsingFailed, "Invalid URL: " + link);
}
}
}

23
app/src/main/res/layout/fragment_remoterss.xml

@ -23,17 +23,20 @@ @@ -23,17 +23,20 @@
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/remoterss_no_files"
android:text="@string/remoterss_loading"
android:gravity="center"
android:id="@+id/remoterss_no_files_message"/>
android:id="@+id/remoterss_status_message"/>
<ListView
android:id="@+id/torrents_list"
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="multipleChoiceModal"
android:clipToPadding="false"
tools:listitem="@layout/list_item_remoterssitem"
tools:visibility="visible"/>
android:layout_height="match_parent">
<ListView
android:id="@+id/torrents_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
tools:listitem="@layout/list_item_remoterssitem"
tools:visibility="visible"/>
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>

1
app/src/main/res/values/strings.xml

@ -214,6 +214,7 @@ @@ -214,6 +214,7 @@
<string name="remoterss_filter_allrecent">(All recent)</string>
<string name="remoterss_no_files">No torrent files found.\n\nAre your RSS feeds configured correctly?</string>
<string name="remoterss_loading">Loading RSS feeds…</string>
<string name="widget_loading">Loading&#8230;</string>
<string name="widget_opentransdroid">Open Transdroid</string>

Loading…
Cancel
Save