diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2f4be72..a3f0fbd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -105,5 +105,8 @@
+
diff --git a/app/src/main/java/org/pyload/android/client/pyLoad.java b/app/src/main/java/org/pyload/android/client/pyLoad.java
index cd50b0e..ec83246 100644
--- a/app/src/main/java/org/pyload/android/client/pyLoad.java
+++ b/app/src/main/java/org/pyload/android/client/pyLoad.java
@@ -1,15 +1,21 @@
package org.pyload.android.client;
-import java.io.File;
-import java.io.FileInputStream;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Locale;
-
import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
-import android.view.*;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.TabHost;
+
+import androidx.core.view.MenuItemCompat;
import org.pyload.android.client.components.FragmentTabsPager;
import org.pyload.android.client.dialogs.AccountDialog;
@@ -18,31 +24,26 @@
import org.pyload.android.client.fragments.QueueFragment;
import org.pyload.android.client.module.Eula;
import org.pyload.android.client.module.GuiTask;
+import org.pyload.android.client.services.clicknload.ClickNLoadService;
import org.pyload.thrift.Destination;
import org.pyload.thrift.PackageDoesNotExists;
import org.pyload.thrift.Pyload.Client;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.net.ConnectivityManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import android.widget.TabHost;
-import androidx.core.view.MenuItemCompat;
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Locale;
public class pyLoad extends FragmentTabsPager
{
private pyLoadApp app;
-
// keep reference to set indeterminateProgress
private MenuItem refreshItem;
/** Called when the activity is first created. */
-
public void onCreate(Bundle savedInstanceState)
{
@@ -90,6 +91,8 @@ public void onCreate(Bundle savedInstanceState)
spec = mTabHost.newTabSpec(title).setIndicator(title,
res.getDrawable(tab_collector));
mTabsAdapter.addTab(spec, CollectorFragment.class, null);
+
+ startClickNLoadService();
}
@Override
@@ -359,4 +362,16 @@ public MenuItem getRefreshItem()
{
return refreshItem;
}
-}
+
+ private void startClickNLoadService() {
+ if(app.prefs.getBoolean("check_box_clicknload", false)){
+ Intent i= new Intent(getApplicationContext(), ClickNLoadService.class);
+ i.setAction("START");
+ int port = Integer.parseInt(app.prefs.getString("edit_text_clicknload_port", "9666"));
+ i.putExtra("port", port);
+
+ getApplicationContext().startService(i);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/pyload/android/client/pyLoadApp.java b/app/src/main/java/org/pyload/android/client/pyLoadApp.java
index a47d299..00bee60 100644
--- a/app/src/main/java/org/pyload/android/client/pyLoadApp.java
+++ b/app/src/main/java/org/pyload/android/client/pyLoadApp.java
@@ -14,6 +14,7 @@
import android.annotation.TargetApi;
import android.content.Context;
+import android.os.Looper;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -332,4 +333,13 @@ public boolean getCaptchaNotificationShown()
return captchaNotificationShown;
}
+ public void showToast(final String text, final int duration){
+ new Handler(Looper.getMainLooper()).post(new Runnable(){
+ @Override
+ public void run() {
+ Toast.makeText(getBaseContext(), text, duration).show();
+ }
+ });
+ }
+
}
diff --git a/app/src/main/java/org/pyload/android/client/services/clicknload/ClickNLoadService.java b/app/src/main/java/org/pyload/android/client/services/clicknload/ClickNLoadService.java
new file mode 100644
index 0000000..68d296d
--- /dev/null
+++ b/app/src/main/java/org/pyload/android/client/services/clicknload/ClickNLoadService.java
@@ -0,0 +1,51 @@
+package org.pyload.android.client.services.clicknload;
+
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+import org.pyload.android.client.pyLoadApp;
+
+import java.util.concurrent.Executors;
+
+public class ClickNLoadService extends Service {
+
+ private final static String LOGTAG = "ClickNLoad Service";
+
+ private ClickNLoadTask clickNLoadTask;
+ private int port;
+
+ @Override
+ public int onStartCommand(final Intent intent, int flags, int startId) {
+
+ if (intent != null) {
+ String action = intent.getAction();
+ port = intent.getExtras().getInt("port");
+ switch(action) {
+ case "START": startService(); break;
+ case "STOP": stopService(); break;
+ default: Log.d(LOGTAG, "This should never happen. No action in the received intent");
+ }
+ } else {
+ Log.d(LOGTAG, "with a null intent. It has been probably restarted by the system.");
+ }
+
+ return Service.START_STICKY;
+ }
+
+ private void stopService() {
+ clickNLoadTask.stop();
+ }
+
+ public void startService() {
+ clickNLoadTask = new ClickNLoadTask(port, (pyLoadApp) getApplicationContext());
+ Executors.newSingleThreadExecutor().submit(clickNLoadTask);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/app/src/main/java/org/pyload/android/client/services/clicknload/ClickNLoadTask.java b/app/src/main/java/org/pyload/android/client/services/clicknload/ClickNLoadTask.java
new file mode 100644
index 0000000..b3fca86
--- /dev/null
+++ b/app/src/main/java/org/pyload/android/client/services/clicknload/ClickNLoadTask.java
@@ -0,0 +1,124 @@
+package org.pyload.android.client.services.clicknload;
+
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.Toast;
+
+import org.pyload.android.client.R;
+import org.pyload.android.client.pyLoadApp;
+import org.pyload.thrift.Destination;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URLDecoder;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class ClickNLoadTask implements Runnable{
+
+ private final static String LOGTAG= "ClickNLoadTask";
+
+ private volatile boolean stopped = false;
+ private int port;
+ private pyLoadApp app;
+
+ public ClickNLoadTask(int port, pyLoadApp app){
+ this.port = port;
+ this.app = app;
+
+ app.prefs.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ //stop if clicknload gets disabled
+ if(key.equals("check_box_clicknload") && !sharedPreferences.getBoolean(key, true)){
+ stop();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void run() {
+ Socket clientSocket = null;
+ BufferedReader in;
+ PrintStream out;
+ ServerSocket serverSocket = null;
+
+ while (!stopped) {
+
+ try {
+ if (serverSocket != null) {
+ serverSocket.close();
+ clientSocket.close();
+ }
+ serverSocket = new ServerSocket(port);
+ clientSocket = serverSocket.accept();
+
+ Log.d(LOGTAG, "Receiving ClickNLoad Event");
+ in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ out = new PrintStream(clientSocket.getOutputStream());
+ } catch (IOException e) {
+ Log.e(LOGTAG, "Socket could not be opened", e);
+ stop();
+ break;
+ }
+
+ try {
+ String input;
+ while ((input = in.readLine()) != null) {
+ if (input.startsWith("source")) {
+ List urlList = getURLParamsAsMap(input).get("urls");
+ app.getClient().addPackage("TestName", urlList, Destination.Collector);
+ app.showToast(String.format(getLocalizedResources(app).getString(R.string.clicknload_toast_msg), urlList.size()), Toast.LENGTH_LONG);
+ }
+ }
+ out.println("success");
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Data could not be parsed");
+ break;
+ }
+ }
+ }
+
+ public static Map> getURLParamsAsMap(String parameters) throws UnsupportedEncodingException {
+ final Map> parameterMap = new LinkedHashMap<>();
+ final String[] pairs = parameters.split("&");
+ for (String pair : pairs) {
+ final int idx = pair.indexOf("=");
+ final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair;
+ if (!parameterMap.containsKey(key)) {
+ parameterMap.put(key, new LinkedList());
+ }
+ final String[] values = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8").split("\\r?\\n") : new String[0];
+ for (String value : values) {
+ parameterMap.get(key).add(value);
+ }
+ }
+ return parameterMap;
+ }
+
+ public void stop() {
+ stopped = true;
+ }
+
+ Resources getLocalizedResources(Context context) {
+ Configuration conf = context.getResources().getConfiguration();
+ conf = new Configuration(conf);
+ conf.setLocale(Locale.getDefault());
+ Context localizedContext = context.createConfigurationContext(conf);
+ return localizedContext.getResources();
+ }
+}
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 89cc4c9..d9bb24e 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -53,6 +53,11 @@
Bitte geben Sie den Text ein
Tabfarbe invertieren
Du kannst das Tab-Aussehen ändern, damit es besser zu deinem System Theme passt.
+ Aktiviere Click\'n\'Load
+ Lässt die App auf Click\'n\'Load Verbindungen reagieren.
+ Click\'n\'Load Port
+ Der Server Port für Click\'n\'Load.
+ Paket mit %d Links empfangen. Zum Collector gesendet
SSL Verbindung
Eine sichere Verbindung zum Server aufbauen, wenn SSL aktiviert wurde.
Bestätige das SSL Zertifikat
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 21dc99b..37d033a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -58,6 +58,11 @@
Enter captcha to continue downloading.
Invert tab icon color
You may change the tab icon layout if it fits better to your theme.
+ Enable Click\'n\'Load
+ Have the app listen for Click\'n\'Load connections.
+ Click\'n\'Load Port
+ Server Port for Click\'n\'Load.
+ Received a package with %d links. Send to Collector
SSL Connection
Establish a secure connection to the core if you activated SSL
Validate SSL Certificate
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 3fbd436..805a1b3 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -12,8 +12,25 @@
-
-
+
+
+
+