Browse Source

Added qt integr8ion with mein srthax shit [[=[=[=[=[==[=[=[

Wazakindjes 10 months ago
parent
commit
6bafdfe222

+ 4 - 2
README.md

@@ -34,9 +34,11 @@ __If enabled in the settings, this entire activity can be shown on the lock scre
 
 7. Extra error information when applicable, which may be the raw JSON as received from Kodi. =]
 
-8. The (re)store functionality is so you can save your playlist's current position (including time as you can see), which you can quickly restore so you don't have to try and remember that shit yourself. When rest0ring, it checks the current play/pause status and repauses that shit if it wasn't playing before either. Also, if the "playlist" (aka "Now Playing" shit) changed it will try to find the st0red vidy0 in the list by name.
+8. Integration with mein [srthax](https://gitgud.malvager.net/Wazakindjes/srthax) shit, so you can correct subs as you watch something. =]]] This assumes your subtitles are all together in one directory (e.g. `/media/subtitles`), plus that the movie's filename matches the subtitle filename (except for the extension of course ;]). Apparently the Kodi API doesn't return the actual path to the subtitle it's using, so doing it like this is the only reliable way really.
 
-9. Area for the shortcuts y0. The buttons are rendered in a grid-based layout which will wrap them onto new "lines" (or rows) automatically when necessary.
+9. The (re)store functionality is so you can save your playlist's current position (including time as you can see), which you can quickly restore so you don't have to try and remember that shit yourself. When rest0ring, it checks the current play/pause status and repauses that shit if it wasn't playing before either. Also, if the "playlist" (aka "Now Playing" shit) changed it will try to find the st0red vidy0 in the list by name.
+
+10. Area for the shortcuts y0. The buttons are rendered in a grid-based layout which will wrap them onto new "lines" (or rows) automatically when necessary.
 
 There's also an optional persistent notification which will be shown on the l0cc screen as well, so you won't have to unlock that shit just to skip some shit. ;3
 ![scr0t](./ass/scr0t2.png)

BIN
app/k0di.apk


+ 1 - 1
app/src/app_k0di/src/main/AndroidManifest.xml

@@ -2,7 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 	xmlns:tools="http://schemas.android.com/tools"
 	package="com.jemoeder.lief.k0di"
-	android:versionName="1.1.0">
+	android:versionName="1.2.0">
 
 	<!-- Need an internet connection to work 0bv lol -->
 	<uses-permission android:name="android.permission.INTERNET" />

+ 35 - 0
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/EditTextMinMax.java

@@ -0,0 +1,35 @@
+package com.jemoeder.lief.k0di;
+
+import android.text.InputFilter;
+import android.text.Spanned;
+
+public class EditTextMinMax implements InputFilter {
+	private final int min;
+	private final int max;
+
+	public EditTextMinMax(int min, int max) {
+		this.min = min;
+		this.max = max;
+	}
+
+	/*public EditTextMinMax(String min, String max) {
+		this.min = Integer.parseInt(min);
+		this.max = Integer.parseInt(max);
+	}*/
+
+	@Override
+	public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
+		try {
+			int input = Integer.parseInt(dest.toString() + source.toString());
+			if(isInRange(min, max, input))
+				return null;
+		} catch(Exception fuckoff) { /* No flying fucks given */ }
+		return "";
+	}
+
+	private boolean isInRange(int a, int b, int c) {
+		if(b > a)
+			return (c >= a && c <= b);
+		return (c >= b && c <= a);
+	}
+}

+ 126 - 16
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/MainActivity.java

@@ -19,6 +19,7 @@ import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PorterDuff;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -32,12 +33,14 @@ import android.support.v4.app.ActivityCompat;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.AppCompatActivity;
 
+import android.text.InputFilter;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
 import android.view.DragEvent;
 import android.view.Gravity;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -76,6 +79,9 @@ public class MainActivity extends AppCompatActivity {
 	private String jsonpot;
 	private String user;
 	private String pass;
+	private String serbur_subh4x;
+	private String pot_subh4x;
+	private String authkey_subh4x;
 	private boolean notifactive;
 	int ping;
 
@@ -83,6 +89,7 @@ public class MainActivity extends AppCompatActivity {
 	private boolean coldstart = true;
 	boolean connecting = false;
 	boolean reconnecting = false;
+	boolean subh4x_working = false;
 	Socket muhsock;
 	PrintWriter muhsock_out;
 	InputStreamReader muhsock_in;
@@ -90,7 +97,7 @@ public class MainActivity extends AppCompatActivity {
 	private int rpcid = 1;
 
 	// Sending commands and getting em output
-	muhk0di k0di;
+	public muhk0di k0di;
 
 	// Snackbar yo
 	private CoordinatorLayout muhparent;
@@ -105,6 +112,10 @@ public class MainActivity extends AppCompatActivity {
 	private TextView connstatus;
 	private TextView errortxt;
 	private int btn_back_drag;
+	public EditText subh4x_h;
+	public EditText subh4x_m;
+	public EditText subh4x_s;
+	private EditText subh4x_timeshift;
 
 	// Shit related to (re)st0re poop
 	private TextView st0rem_current;
@@ -174,6 +185,23 @@ public class MainActivity extends AppCompatActivity {
 		setButtonSize(st0rem_restore);
 		setButtonSize(findViewById(R.id.mainact_st0rem_clear));
 
+		Button subh4x_doit = findViewById(R.id.mainact_subh4x_doit);
+		Button subh4x_getcurrent = findViewById(R.id.mainact_subh4x_getcurrent);
+		Button subh4x_resettime = findViewById(R.id.mainact_subh4x_resettime);
+		controlviews.add(subh4x_doit);
+		controlviews.add(subh4x_getcurrent);
+		setButtonSize(subh4x_doit);
+		setButtonSize(subh4x_getcurrent);
+		setButtonSize(subh4x_resettime);
+
+		subh4x_h = findViewById(R.id.mainact_subh4x_time_h);
+		subh4x_m = findViewById(R.id.mainact_subh4x_time_m);
+		subh4x_s = findViewById(R.id.mainact_subh4x_time_s);
+		subh4x_timeshift = findViewById(R.id.mainact_subh4x_timeshift);
+		subh4x_h.setFilters(new InputFilter[]{ new EditTextMinMax(0, 24)});
+		subh4x_m.setFilters(new InputFilter[]{ new EditTextMinMax(0, 59)});
+		subh4x_s.setFilters(new InputFilter[]{ new EditTextMinMax(0, 59)});
+
 		wrapass.st0rem_name = wrapass.muhprefs.getString("n0pref_st0rem_name", null);
 		wrapass.st0rem_pos = wrapass.muhprefs.getString("n0pref_st0rem_pos", null);
 		wrapass.st0rem_time = wrapass.muhprefs.getString("n0pref_st0rem_time", null);
@@ -244,6 +272,11 @@ public class MainActivity extends AppCompatActivity {
 		wrapass.sockettimeout = wrapass.pref_string2int("prefs_sockettimeout", 100, 100, 9999);
 		wrapass.playwait = wrapass.pref_string2int("prefs_playwait", 2000, 100, 9999);
 
+		serbur_subh4x = wrapass.muhprefs.getString("prefs_serbur_subh4x", "LOLNOPE");
+		pot_subh4x = wrapass.muhprefs.getString("prefs_pot_subh4x", "6971");
+		authkey_subh4x = wrapass.muhprefs.getString("prefs_authkey_subh4x", "LOLNOPE");
+		wrapass.sockettimeout_subh4x = wrapass.pref_string2int("prefs_sockettimeout_subh4x", 2000, 1000, 9999);
+
 		int tmp_lastorder = wrapass.muhprefs.getInt("n0pref_lastcmd", -1);
 		if(tmp_lastorder > (wrapass.sh0rtcuts.length() - 1))
 			tmp_lastorder = -1;
@@ -289,6 +322,23 @@ public class MainActivity extends AppCompatActivity {
 		return true;
 	}
 
+	@Override
+	public boolean dispatchTouchEvent(MotionEvent event) {
+		if(event.getAction() == MotionEvent.ACTION_DOWN) {
+			View v = getCurrentFocus();
+			if(v instanceof EditText) {
+				Rect outRect = new Rect();
+				v.getGlobalVisibleRect(outRect);
+				if(!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
+					v.clearFocus();
+					InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+					imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
+				}
+			}
+		}
+		return super.dispatchTouchEvent(event);
+	}
+
 	void setst0remCurrent() {
 		if(wrapass.st0rem_name != null) {
 			String txt = wrapass.st0rem_name;
@@ -408,21 +458,82 @@ public class MainActivity extends AppCompatActivity {
 	private void setButtonSize(View v) {
 		if(v == null)
 			return;
-		Button btn = (Button) v;
+		Button btn = (Button)v;
 		btn.setMinWidth(dimen_btn_minwidth);
 		btn.setPadding(dimen_btn_padding_h, dimen_btn_padding_v, dimen_btn_padding_h, dimen_btn_padding_v);
 	}
 
+	// Implying I'm gonna use a fucking StringBuilder to just add 1 or 2 zeroes .-.
+	@SuppressWarnings("StringConcatenationInLoop")
+	public String subh4x_padtime(String t0ime) {
+		while(t0ime.length() < 2)
+			t0ime = "0" + t0ime;
+		return t0ime;
+	}
+
 	// Because IntelliJ is too retarded to get that the XML layouts' onClick attributes require a View argument for this function
 	@SuppressWarnings("unused")
-	public void st0remd0it(View v) {
-		long unix = currentTimeMillis();
-		if(wrapass.lastcmd_time > 0 && (unix - wrapass.lastcmd_time) <= 1000)
-			return;
-		wrapass.lastcmd_time = unix;
+	public void st0rem_d0it(View v) {
 		wrapass.muhcmds.add(new k0dicmd(k0diWrapper.CMD_STORE, null, null, null));
 	}
 
+	private void subh4xem(String cmd, String cmd_arg) {
+		boolean rip = false;
+		int pot_i = 0;
+		try {
+			pot_i = Integer.parseInt(pot_subh4x);
+		}
+		catch(Exception fuckoff) { /* No flying fucks given */ }
+
+		if(serbur_subh4x == null || serbur_subh4x.isEmpty() || serbur_subh4x.equals("LOLNOPE") || serbur_subh4x.equals("192.168.1.0")) {
+			setStatus(R.color.RIP, R.string.main_status_rip, R.string.main_status_errtxt_default_serbur);
+			rip = true;
+		}
+		else if(pot == null || pot_i <= 1024 || pot_i >= 65535) {
+			setStatus(R.color.RIP, R.string.main_status_rip, R.string.main_status_errtxt_invalidport);
+			rip = true;
+		}
+
+		if(rip)
+			return;
+
+		if(subh4x_working || k0di == null || reconnecting)
+			return;
+		subh4x_working = true;
+		setStatus(R.color.colorAccent, R.string.main_status_working, "");
+		subh4x muhapi = new subh4x(this, authkey_subh4x, serbur_subh4x, pot_i, cmd, cmd_arg);
+		muhapi.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+	}
+
+	@SuppressWarnings("unused")
+	public void subh4x_d0it(View v) {
+		String h = subh4x_padtime(subh4x_h.getText().toString());
+		String m = subh4x_padtime(subh4x_m.getText().toString());
+		String s = subh4x_padtime(subh4x_s.getText().toString());
+		String shift = subh4x_timeshift.getText().toString();
+		String cmd_arg = String.format("%s:%s:%s %s", h, m, s, shift);
+		subh4xem(k0diWrapper.CMD_SUBHAX_DOIT, cmd_arg);
+	}
+
+	@SuppressWarnings("unused")
+	public void subh4x_getcurrent(View v) {
+		subh4xem(k0diWrapper.CMD_SUBHAX_GETCUR, null);
+	}
+
+	@SuppressWarnings("unused")
+	public void subh4x_resettime(View v) {
+		View focused = getCurrentFocus();
+		subh4x_h.setText(R.string.subh4x_start_default);
+		subh4x_m.setText(R.string.subh4x_start_default);
+		subh4x_s.setText(R.string.subh4x_start_default);
+		//subh4x_timeshift.setText(R.string.subh4x_start_default_short);
+		if(focused != null) {
+			focused.requestFocus();
+			if(focused instanceof EditText)
+				((EditText)focused).selectAll();
+		}
+	}
+
 	@SuppressWarnings("unused")
 	public void st0remRestore(View v) {
 		if(wrapass.st0rem_name == null) {
@@ -433,10 +544,6 @@ public class MainActivity extends AppCompatActivity {
 			doSnackbar("Fat fucking rip (st0red information is corrupted)", Snackbar.LENGTH_LONG, true);
 			return;
 		}
-		long unix = currentTimeMillis();
-		if(wrapass.lastcmd_time > 0 && (unix - wrapass.lastcmd_time) <= 2000)
-			return;
-		wrapass.lastcmd_time = unix;
 		wrapass.muhcmds.add(new k0dicmd(k0diWrapper.CMD_RESTORE, wrapass.st0rem_name, wrapass.st0rem_pos, wrapass.st0rem_time));
 	}
 
@@ -644,6 +751,11 @@ public class MainActivity extends AppCompatActivity {
 	}
 
 	// Also a simple wrappur for displaying em snackbars
+	public void doSnackbar(int pmi, int pl, boolean waserr) {
+		String pm = muhres.getString(pmi);
+		doSnackbar(pm, pl, waserr);
+	}
+
 	public void doSnackbar(String pm, int pl, boolean waserr) {
 		if(wrapass.backgrounded) {
 			// When backgrounded Snackbars won't be visible anyways, so forward that shit to a t0ast
@@ -780,7 +892,7 @@ public class MainActivity extends AppCompatActivity {
 		// Display message and do that shit
 		rpcid = 1;
 		setStatus(R.color.colorAccent, R.string.main_status_connecting, (reconnecting ? R.string.main_status_errtxt_reconnect : R.string.NOSTRING));
-		connectAPI capi = new connectAPI(this, serbur, pot_i, jsonpot_i, user, pass);
+		connectAPI_kodi capi = new connectAPI_kodi(this, serbur, pot_i, jsonpot_i, user, pass);
 		capi.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
 	}
 
@@ -806,12 +918,10 @@ public class MainActivity extends AppCompatActivity {
 					break;
 				buffer = new char[arrsize];
 			}
-		}
-		catch(SocketTimeoutException fuckoff) {
+		} catch(SocketTimeoutException fuckoff) {
 			// No flying fucks given (happens when read() don't return shit lol)
 			throw fuckoff;
-		}
-		catch(Exception fuckoff) {
+		} catch(Exception fuckoff) {
 			throw new Exception(fuckoff.getMessage());
 		}
 		return muhdata.toString();

+ 5 - 0
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/SettingsActivity.java

@@ -60,6 +60,11 @@ public class SettingsActivity extends AppCompatActivity {
 			bindPreferenceSummaryToValue(findPreference("prefs_sockettimeout"));
 			bindPreferenceSummaryToValue(findPreference("prefs_playwait"));
 			bindPreferenceSummaryToValue(findPreference("prefs_versionbuild"));
+
+			bindPreferenceSummaryToValue(findPreference("prefs_authkey_subh4x"));
+			bindPreferenceSummaryToValue(findPreference("prefs_serbur_subh4x"));
+			bindPreferenceSummaryToValue(findPreference("prefs_pot_subh4x"));
+			bindPreferenceSummaryToValue(findPreference("prefs_sockettimeout_subh4x"));
 		}
 	}
 }

+ 2 - 2
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/connectAPI.java

@@ -17,7 +17,7 @@ import java.util.Locale;
 
 // Thread for setting up the connection
 @SuppressLint("StaticFieldLeak")
-class connectAPI extends AsyncTask<Void, Void, Void> {
+class connectAPI_kodi extends AsyncTask<Void, Void, Void> {
 	// Gotta pass along some preferences
 	private final String serbur;
 	private final int pot;
@@ -36,7 +36,7 @@ class connectAPI extends AsyncTask<Void, Void, Void> {
 	private PrintWriter muhsock_out;
 	private InputStreamReader muhsock_in;
 
-	connectAPI(MainActivity a, String b, int c, int d, String e, String f) {
+	connectAPI_kodi(MainActivity a, String b, int c, int d, String e, String f) {
 		status = R.string.main_status_rip;
 		err = R.string.NOSTRING;
 		errstr = "";

+ 4 - 0
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/k0diWrapper.java

@@ -27,6 +27,7 @@ public class k0diWrapper extends Application {
 	public SharedPreferences.Editor muhprefs_ed;
 	public boolean stickydrawer = false;
 	public int sockettimeout = 100; // 100ms by default imo tbh famalmlamlma
+	public int sockettimeout_subh4x = 2000; // 2000ms by default imo tbh famalmlamlma
 	public int playwait = 2000; // 2000ms l0l
 
 	// Command shit etc
@@ -37,6 +38,9 @@ public class k0diWrapper extends Application {
 	public final static String CMD_STORE = "st0rem";
 	public final static String CMD_RESTORE = "rest0rem";
 
+	public final static String CMD_SUBHAX_GETCUR = "subh4x_getcurrent";
+	public final static String CMD_SUBHAX_DOIT = "subh4x_d0it";
+
 	public String st0rem_name = null;
 	public String st0rem_pos = null;
 	public String st0rem_time = null;

+ 47 - 19
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/muhk0di.java

@@ -18,7 +18,7 @@ import static java.lang.System.currentTimeMillis;
 
 // Thread for sending that shit
 @SuppressLint("StaticFieldLeak")
-class muhk0di extends AsyncTask<Void, Void, Void> {
+public class muhk0di extends AsyncTask<Void, Void, Void> {
 	// Some globals cuz we check some of these in onPostExecute as well
 	private int col;
 	private int status;
@@ -40,19 +40,12 @@ class muhk0di extends AsyncTask<Void, Void, Void> {
 		long gottaping = currentTimeMillis() + (main.ping * 1000); // Also ping interval
 
 		while(main.muhsock != null && !main.reconnecting) {
-			// We may receive shit about other clients too, so try to discard that fucking shit
-			try {
-				// Set the underlying read() call's timeout to 100ms so it doesn't keep fucking blocking until it has data
-				main.muhsock.setSoTimeout(100);
-				main.readKodi(main.muhsock_in);
-			} catch(Exception fuckoff) { /* No flying fucks given */ }
 			try {
+				if(main.muhsock_in.ready())
+					k0diFlushJunk();
+				setk0diSocketTimeout();
 				int cmdsize = main.wrapass.muhcmds.size(); // Cuz cbf accessing this in a (for) loop either ;]
 				if(cmdsize > 0) {
-					// Maybe (re)adjust the socket timeout y0
-					if(main.wrapass.sockettimeout != 100) {
-						try { main.muhsock.setSoTimeout(main.wrapass.sockettimeout); } catch(Exception fuckoff) { /* No flying fucks given */ }
-					}
 					hasplayer = false; // Always re-check for the vidya player l0l
 					for(int cmdi = 0; cmdi < cmdsize; cmdi++) {
 						k0dicmd kcmd = main.wrapass.muhcmds.get(cmdi);
@@ -146,8 +139,25 @@ class muhk0di extends AsyncTask<Void, Void, Void> {
 		setMainStatus(R.color.colorAccent, R.string.main_status_working, str, snackstr, snacklength);
 	}
 
+	public void k0diFlushJunk() {
+		// We may receive shit about other clients too, so try to discard that fucking shit
+		try {
+			// Set the underlying read() call's timeout to 100ms so it doesn't keep fucking blocking until it has data
+			main.muhsock.setSoTimeout(100);
+			main.readKodi(main.muhsock_in);
+		} catch(Exception fuckoff) { /* No flying fucks given */ }
+	}
+
+	public void setk0diSocketTimeout() {
+		// Maybe (re)adjust the socket timeout y0
+		if(main.wrapass.sockettimeout != 100) {
+			try { main.muhsock.setSoTimeout(main.wrapass.sockettimeout); }
+			catch(Exception fuckoff) { /* No flying fucks given */ }
+		}
+	}
+
 	@SuppressWarnings("SameParameterValue")
-	private String k0di_writerecv(String cmd, int plsw8m8) throws Exception {
+	public String k0di_writerecv(String cmd, int plsw8m8) throws Exception {
 		// Write that shit and listen for een resp0nse (after a lil delay 0bv)
 		String ret = null;
 		setWorking("", "", 99);
@@ -165,7 +175,7 @@ class muhk0di extends AsyncTask<Void, Void, Void> {
 		return ret;
 	}
 
-	private JSONObject checkemJSONObj(String raw, @SuppressWarnings("SameParameterValue") JSONObject jsonobj, String needkey, String needkey2, String custerr) {
+	public JSONObject checkemJSONObj(String raw, @SuppressWarnings("SameParameterValue") JSONObject jsonobj, String needkey, String needkey2, String custerr) {
 		try {
 			JSONObject jayson = (jsonobj != null ? null : new JSONObject(raw));
 			if(jayson != null)
@@ -237,6 +247,9 @@ class muhk0di extends AsyncTask<Void, Void, Void> {
 	}
 
 	private JSONObject getk0diProperties() throws Exception {
+		if(!hasplayer && !(hasplayer = getk0diPlayer(false)))
+			return null;
+
 		String props = k0di_writerecv(main.getKodiCmd(R.string.jsonrpc_getprops, null, null), 0);
 		if(props == null) {
 			setMainStatus(R.color.RIP, R.string.main_status_gucci, "", "No data returned for Player.GetProperties", Snackbar.LENGTH_LONG);
@@ -245,26 +258,41 @@ class muhk0di extends AsyncTask<Void, Void, Void> {
 		return checkemJSONObj(props, null, "time", null, "Nothing is playing at the moment");
 	}
 
-	private void getk0diStore() throws Exception {
-		int cursec;
-		int pos;
+	public JSONObject getk0diCurrent() throws Exception {
 		JSONObject jayson_props = getk0diProperties();
 		if(jayson_props == null)
-			return;
+			return null;
 
 		String item = k0di_writerecv(main.getKodiCmd(R.string.jsonrpc_getitem, null, null), 0);
 		if(item == null) {
 			setMainStatus(R.color.RIP, R.string.main_status_gucci, "", "No data returned for Player.GetItem", Snackbar.LENGTH_LONG);
-			return;
+			return null;
 		}
 
 		JSONObject jayson_item = checkemJSONObj(item, null, "item", "label", "Nothing is playing at the moment");
 		if(jayson_item == null)
+			return null;
+
+		JSONObject ret = new JSONObject();
+		ret.put("props", jayson_props);
+		ret.put("item", jayson_item);
+		return ret;
+	}
+
+	private void getk0diStore() throws Exception {
+		int cursec;
+		int pos;
+
+		JSONObject cur_ret = getk0diCurrent();
+		if(cur_ret == null)
 			return;
 
+		JSONObject jayson_props = cur_ret.getJSONObject("props");
+		JSONObject jayson_item = cur_ret.getJSONObject("item");
+		JSONObject jayson_time = jayson_props.getJSONObject("time");
+
 		final String name = jayson_item.getString("label");
 		pos = jayson_props.getInt("position");
-		JSONObject jayson_time = jayson_props.getJSONObject("time");
 		cursec = (jayson_time.getInt("hours") * 60 * 60) + (jayson_time.getInt("minutes") * 60) + jayson_time.getInt("seconds");
 
 		String pos_s = String.valueOf(pos);

+ 191 - 0
app/src/app_k0di/src/main/java/com/jemoeder/lief/k0di/subh4x.java

@@ -0,0 +1,191 @@
+package com.jemoeder.lief.k0di;
+
+import android.annotation.SuppressLint;
+import android.os.AsyncTask;
+import android.support.design.widget.Snackbar;
+
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+@SuppressLint("StaticFieldLeak")
+public class subh4x extends AsyncTask<Void, Void, Void> {
+	// Gotta pass along some preferences
+	private final String authkey;
+	private final String serbur;
+	private final String cmd;
+	private final int pot_i;
+	private String cmd_arg;
+
+	// Same globals as before lol
+	private int status;
+	private int err;
+	private String errstr;
+	private final MainActivity main;
+	private String ret_h;
+	private String ret_m;
+	private String ret_s;
+
+	// Also some only relevant for this thread
+	SSLSocket muhsock;
+	PrintWriter muhsock_out;
+	BufferedReader muhsock_in;
+
+	subh4x(MainActivity a, String b, String c, int d, String e, String f) {
+		status = R.string.main_status_rip;
+		err = R.string.NOSTRING;
+		errstr = "";
+		main = a;
+		authkey = b;
+		serbur = c;
+		pot_i = d;
+		cmd = e;
+		cmd_arg = f;
+	}
+
+	@Override
+	protected Void doInBackground(Void... arg0) {
+		try {
+			InetAddress serverAddr = InetAddress.getByName(serbur); // Cuz we prolly wanna support DNS too and not just IPs xd
+			SSLSocketFactory sslf = (SSLSocketFactory)SSLSocketFactory.getDefault();
+
+			// Set up a socket and start em handshaek (give it 5 seconds to complete a read for this)
+			muhsock = (SSLSocket)sslf.createSocket(serverAddr, pot_i);
+			muhsock.setSoTimeout(5000);
+			muhsock.startHandshake();
+
+			// 15 seconds for reading the responses
+			muhsock.setSoTimeout(15000);
+
+			// Set up IO streams and write that shit fam
+			muhsock_out = new PrintWriter(muhsock.getOutputStream());
+			muhsock_in = new BufferedReader(new InputStreamReader(muhsock.getInputStream()));
+			muhsock_out.write("!auth " + authkey + "\r\n");
+			if(muhsock_out.checkError()) {
+				throw new IOException("Unable to write to socket (unknown error)");
+			}
+
+			String muhdata = muhsock_in.readLine();
+			if(muhdata == null || !muhdata.matches("Accepted.*")) {
+				// Not actually a null pointer but cbf setting up a custom Exception class just for these 2 lines xd
+				// Also there's actually zero chance of there being an actuall null pointer here sooo
+				throw new NullPointerException("Auth failed lol");
+			}
+
+			// In all cases we first need to ask Kodi about the current pleylist item (either to get the file name or current time)
+			// This actually goes through Kodi and not the subh4x server ;]
+			JSONObject cur_ret = main.k0di.getk0diCurrent();
+			if(cur_ret != null) {
+				JSONObject jayson_props = cur_ret.getJSONObject("props");
+				JSONObject jayson_item = cur_ret.getJSONObject("item");
+				JSONObject jayson_time = jayson_props.getJSONObject("time");
+
+				if(cmd.equals(k0diWrapper.CMD_SUBHAX_DOIT)) {
+					cmd_arg += " " + jayson_item.getString("label");
+
+					muhsock_out.write("!srthax " + cmd_arg + "\r\n");
+					if(muhsock_out.checkError()) {
+						throw new IOException("Unable to write to socket (unknown error)");
+					}
+
+					// srthax shouldn't return anything on success ;]
+					muhsock.setSoTimeout(main.wrapass.sockettimeout_subh4x);
+					muhdata = null;
+					try {
+						muhdata = muhsock_in.readLine();
+					}
+					catch(Exception fuckoff2) { /* No flying fucks given */ }
+
+					if(muhdata != null && muhdata.length() > 0)
+						throw new Exception(muhdata);
+
+					status = R.string.main_status_gucci;
+				}
+
+				else if(cmd.equals(k0diWrapper.CMD_SUBHAX_GETCUR)) {
+					ret_h = main.subh4x_padtime(String.valueOf(jayson_time.getInt("hours")));
+					ret_m = main.subh4x_padtime(String.valueOf(jayson_time.getInt("minutes")));
+					ret_s = main.subh4x_padtime(String.valueOf(jayson_time.getInt("seconds")));
+					status = R.string.main_status_gucci;
+				}
+
+				else {
+					errstr = "Unknown command: " + cmd;
+				}
+			}
+		} catch(UnknownHostException e) {
+			err = R.string.main_status_errtxt_invalidserver;
+		} catch(IOException e) {
+			errstr = "IO error: " + e.getMessage();
+		} catch(NullPointerException e) {
+			err = R.string.main_status_errtxt_auth;
+		} catch(Exception e) {
+			errstr = e.getMessage();
+		}
+
+		// Always close the API imo tbh famlamlma
+		try {
+			muhsock_out.write("!quit\r\n");
+			muhsock_out.flush();
+			//Thread.sleep(1000);
+		} catch(Exception fuckoff) { /* No flying fucks given */ }
+		return null;
+	}
+
+	@Override
+	protected void onPostExecute(Void result) {
+		// Set status messages according to connection results =]
+		int col = (status == R.string.main_status_gucci ? R.color.gucci : R.color.RIP);
+		if(!errstr.isEmpty()) {
+			main.setStatus(col, status, errstr);
+			main.doSnackbar(errstr, Snackbar.LENGTH_LONG, false);
+		}
+		else {
+			main.setStatus(col, status, err);
+			main.doSnackbar(err, Snackbar.LENGTH_LONG, false);
+		}
+
+		if(col != R.color.RIP) {
+			if(cmd.equals(k0diWrapper.CMD_SUBHAX_DOIT))
+				main.doSnackbar("Ayy hekked em subs fam", Snackbar.LENGTH_LONG, false);
+			else if(cmd.equals(k0diWrapper.CMD_SUBHAX_GETCUR)) {
+				if(ret_h == null)
+					main.subh4x_h.setText(R.string.subh4x_start_default);
+				else
+					main.subh4x_h.setText(ret_h);
+
+				if(ret_m == null)
+					main.subh4x_m.setText(R.string.subh4x_start_default);
+				else
+					main.subh4x_m.setText(ret_m);
+
+				if(ret_s == null)
+					main.subh4x_s.setText(R.string.subh4x_start_default);
+				else
+					main.subh4x_s.setText(ret_s);
+
+				String timestr = String.format("%s:%s:%s", main.subh4x_h.getText().toString(), main.subh4x_m.getText().toString(), main.subh4x_s.getText().toString());
+				main.doSnackbar("Ayy current time: " + timestr, Snackbar.LENGTH_LONG, false);
+			}
+		}
+
+		// Finish up lm0a
+		main.subh4x_working = false;
+		try {
+			// Double try cuz we might not have open streams but we might have an open socket
+			try {
+				muhsock_out.close();
+				muhsock_in.close();
+			} catch(Exception fuckoff3) { /* No flying fucks given */ }
+			muhsock.close();
+		} catch(Exception fuckoff) { /* No flying fucks given */ }
+	}
+}

+ 162 - 3
app/src/app_k0di/src/main/res/layout/activity_main.xml

@@ -5,7 +5,9 @@
 	android:layout_width="match_parent"
 	android:layout_height="match_parent"
 	android:id="@+id/muhparent"
-	tools:context=".MainActivity">
+	tools:context=".MainActivity"
+	android:focusable="true"
+	android:focusableInTouchMode="true">
 
 	<!-- I could probs do this entire XML a little differently/more elegant but idc xd -->
 	<ScrollView
@@ -67,13 +69,170 @@
 			<View
 				android:layout_width="match_parent"
 				android:layout_height="1dp"
-				android:id="@+id/mainact_divider_st0rem"
+				android:id="@+id/mainact_divider_subh4x"
 				android:layout_marginTop="@dimen/main_category_spacing"
 				android:layout_marginEnd="10dp"
 				android:background="@color/divider"
 				app:layout_constraintTop_toBottomOf="@id/mainact_connstatus_errortxt"
 				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text" />
 
+			<TextView
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_header_subh4x"
+				android:layout_marginTop="@dimen/main_divider_spacing"
+				android:text="@string/header_main_subh4x"
+				android:textStyle="bold"
+				android:textSize="@dimen/text_header1"
+				android:textColor="@color/text_header1"
+				app:layout_constraintTop_toBottomOf="@id/mainact_divider_subh4x"
+				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text" />
+
+			<TextView
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/subh4x_start_txt"
+				android:text="@string/subh4x_start_txt"
+				android:textStyle="bold"
+				android:textSize="@dimen/text_content"
+				android:textColor="@color/text_header2"
+				android:layout_marginTop="8dp"
+				app:layout_constraintStart_toStartOf="@id/mainact_header_subh4x"
+				app:layout_constraintTop_toBottomOf="@id/mainact_header_subh4x" />
+			<EditText
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_time_h"
+				android:inputType="number"
+				android:text="@string/subh4x_start_default"
+				android:maxLength="2"
+				android:textColor="@color/text_header1"
+				android:imeOptions="actionNext"
+				android:selectAllOnFocus="true"
+				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text"
+				app:layout_constraintTop_toBottomOf="@id/subh4x_start_txt"
+				android:importantForAutofill="no"
+				tools:ignore="LabelFor" />
+			<EditText
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_time_m"
+				android:inputType="number"
+				android:text="@string/subh4x_start_default"
+				android:maxLength="2"
+				android:textColor="@color/text_header1"
+				android:imeOptions="actionNext"
+				android:selectAllOnFocus="true"
+				app:layout_constraintStart_toEndOf="@id/mainact_subh4x_time_h"
+				app:layout_constraintTop_toTopOf="@id/mainact_subh4x_time_h"
+				android:importantForAutofill="no"
+				tools:ignore="LabelFor" />
+			<EditText
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_time_s"
+				android:inputType="number"
+				android:text="@string/subh4x_start_default"
+				android:maxLength="2"
+				android:textColor="@color/text_header1"
+				android:selectAllOnFocus="true"
+				android:imeOptions="actionNext"
+				app:layout_constraintStart_toEndOf="@id/mainact_subh4x_time_m"
+				app:layout_constraintTop_toTopOf="@id/mainact_subh4x_time_m"
+				android:importantForAutofill="no"
+				tools:ignore="LabelFor" />
+
+			<TextView
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/subh4x_timeshift_txt"
+				android:text="@string/subh4x_timeshift_txt"
+				android:textStyle="bold"
+				android:textSize="@dimen/text_content"
+				android:textColor="@color/text_header2"
+				android:layout_marginTop="16dp"
+				app:layout_constraintStart_toStartOf="@id/subh4x_start_txt"
+				app:layout_constraintTop_toBottomOf="@id/mainact_subh4x_time_s" />
+			<EditText
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_timeshift"
+				android:inputType="numberDecimal|numberSigned"
+				android:text="@string/subh4x_start_default_short"
+				android:textColor="@color/text_header1"
+				android:selectAllOnFocus="true"
+				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text"
+				app:layout_constraintTop_toBottomOf="@id/subh4x_timeshift_txt"
+				android:importantForAutofill="no"
+				tools:ignore="LabelFor" />
+
+			<Button
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_doit"
+				android:minWidth="@dimen/button_minwidth"
+				android:layout_marginTop="8dp"
+				android:layout_marginEnd="8dp"
+				android:paddingTop="@dimen/button_padding_v"
+				android:paddingBottom="@dimen/button_padding_v"
+				android:paddingStart="@dimen/button_padding_h"
+				android:paddingEnd="@dimen/button_padding_h"
+				android:textSize="@dimen/text_header2"
+				android:text="@string/subh4x_doit"
+				android:textAllCaps="false"
+				android:textColor="@color/text_header2"
+				android:onClick="subh4x_d0it"
+				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text"
+				app:layout_constraintTop_toBottomOf="@id/mainact_subh4x_timeshift" />
+
+			<Button
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_getcurrent"
+				android:minWidth="@dimen/button_minwidth"
+				android:layout_marginEnd="8dp"
+				android:paddingTop="@dimen/button_padding_v"
+				android:paddingBottom="@dimen/button_padding_v"
+				android:paddingStart="@dimen/button_padding_h"
+				android:paddingEnd="@dimen/button_padding_h"
+				android:textSize="@dimen/text_header2"
+				android:text="@string/subh4x_getcurrent"
+				android:textAllCaps="false"
+				android:textColor="@color/text_header2"
+				android:onClick="subh4x_getcurrent"
+				app:layout_constraintStart_toEndOf="@id/mainact_subh4x_doit"
+				app:layout_constraintTop_toTopOf="@id/mainact_subh4x_doit" />
+
+			<Button
+				android:layout_width="wrap_content"
+				android:layout_height="wrap_content"
+				android:id="@+id/mainact_subh4x_resettime"
+				android:minWidth="@dimen/button_minwidth"
+				android:layout_marginEnd="8dp"
+				android:paddingTop="@dimen/button_padding_v"
+				android:paddingBottom="@dimen/button_padding_v"
+				android:paddingStart="@dimen/button_padding_h"
+				android:paddingEnd="@dimen/button_padding_h"
+				android:textSize="@dimen/text_header2"
+				android:text="@string/subh4x_resettime"
+				android:textAllCaps="false"
+				android:textColor="@color/text_header2"
+				android:onClick="subh4x_resettime"
+				app:layout_constraintStart_toEndOf="@id/mainact_subh4x_getcurrent"
+				app:layout_constraintTop_toTopOf="@id/mainact_subh4x_getcurrent" />
+
+
+
+			<View
+				android:layout_width="match_parent"
+				android:layout_height="1dp"
+				android:id="@+id/mainact_divider_st0rem"
+				android:layout_marginTop="@dimen/main_category_spacing"
+				android:layout_marginEnd="10dp"
+				android:background="@color/divider"
+				app:layout_constraintTop_toBottomOf="@id/mainact_subh4x_getcurrent"
+				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text" />
+
 			<TextView
 				android:layout_width="wrap_content"
 				android:layout_height="wrap_content"
@@ -100,7 +259,7 @@
 				android:text="@string/st0rem_store"
 				android:textAllCaps="false"
 				android:textColor="@color/text_header2"
-				android:onClick="st0remd0it"
+				android:onClick="st0rem_d0it"
 				app:layout_constraintStart_toStartOf="@id/mainact_connstatus_text"
 				app:layout_constraintTop_toBottomOf="@id/mainact_header_st0rem" />
 			<Button

+ 14 - 0
app/src/app_k0di/src/main/res/values/strings.xml

@@ -36,6 +36,10 @@
 	<string name="prefs_show_lockscreen">Show on lock screen</string>
 	<string name="prefs_show_lockscreen_summary">Displays the entire main activity on the lock screen so it can be used without unl0cking (must lock the screen with the app in the foreground th0)</string>
 
+	<string name="prefs_authkey_subh4x">Auth key</string>
+	<string name="prefs_serbur_subh4x">Server</string>
+	<string name="prefs_pot_subh4x">p0t</string>
+
 	<!-- Shit related to dialog for adding/editing shortcuts -->
 	<string name="dial_addsc_nametxt">Name:</string>
 	<string name="dial_addsc_namehint">Friends Intr0</string>
@@ -74,10 +78,20 @@
 	<string name="main_status_errtxt_default_pass">Password not configured</string>
 	<string name="main_status_errtxt_reconnect">Attempting to close socket cleanly before reconnecting</string>
 
+	<string name="header_main_subh4x">Subtitle h4x lol</string>
 	<string name="header_main_st0rem">(Re)st0re that shit lol</string>
 	<string name="header_main_shortcuts">Skip that shit lol</string>
 	<string name="notification_desc">Skip that shit again lol</string>
 
+	<!-- Related to subtitle h4x -->
+	<string name="subh4x_start_txt">Start time for modifications (format is HH:MM:SS)</string>
+	<string name="subh4x_timeshift_txt">Shift by (seconds)</string>
+	<string name="subh4x_doit">d0it</string>
+	<string name="subh4x_getcurrent">Get current t0ime</string>
+	<string name="subh4x_resettime">Reset t0ime</string>
+	<string name="subh4x_start_default">00</string>
+	<string name="subh4x_start_default_short">0</string>
+
 	<!-- Related to (re)st0re functionalities -->
 	<string name="st0rem_current_header">Currently st0red:</string>
 	<string name="st0rem_current_default">Not a fucking thing lmao</string>

+ 79 - 25
app/src/app_k0di/src/main/res/xml/preferences.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
 	<PreferenceCategory
-		android:title="Connection"
+		android:title="Kodi"
 		android:layout="@layout/preference_category">
 
 		<EditTextPreference
@@ -56,30 +56,6 @@
 			android:title="@string/prefs_pass"
 			android:summary="@string/prefs_pass_summary" />
 
-		<CheckBoxPreference
-			android:key="prefs_notifactive"
-			android:title="@string/prefs_notifactive"
-			android:summary="@string/prefs_notifactive_summary"
-			android:defaultValue="false"/>
-
-		<CheckBoxPreference
-			android:key="prefs_stickydrawer"
-			android:title="@string/prefs_stickydrawer"
-			android:summary="@string/prefs_stickydrawer_summary"
-			android:defaultValue="false"/>
-
-		<CheckBoxPreference
-			android:key="prefs_show_lockscreen"
-			android:title="@string/prefs_show_lockscreen"
-			android:summary="@string/prefs_show_lockscreen_summary"
-			android:defaultValue="false"/>
-
-		<CheckBoxPreference
-			android:key="prefs_autoconnect"
-			android:title="@string/prefs_autoconnect"
-			android:summary="@string/prefs_autoconnect_summary"
-			android:defaultValue="false"/>
-
 		<EditTextPreference
 			android:defaultValue="30"
 			android:inputType="number"
@@ -111,6 +87,84 @@
 			android:title="@string/prefs_playwait" />
 	</PreferenceCategory>
 
+
+	<PreferenceCategory
+		android:title="Subtitle h4x"
+		android:layout="@layout/preference_category">
+
+		<EditTextPreference
+			android:defaultValue="192.168.1.0"
+			android:inputType="text"
+			android:key="prefs_serbur_subh4x"
+			android:maxLines="1"
+			android:selectAllOnFocus="true"
+			android:singleLine="true"
+			android:title="@string/prefs_serbur_subh4x"
+			android:summary="@string/prefs_serbur_subh4x" />
+
+		<EditTextPreference
+			android:defaultValue="6971"
+			android:inputType="number"
+			android:key="prefs_pot_subh4x"
+			android:maxLines="1"
+			android:maxLength="5"
+			android:selectAllOnFocus="true"
+			android:singleLine="true"
+			android:title="@string/prefs_pot_subh4x"
+			android:summary="@string/prefs_pot_subh4x" />
+
+		<EditTextPreference
+			android:defaultValue="1234567890abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQR"
+			android:inputType="text"
+			android:key="prefs_authkey_subh4x"
+			android:maxLines="1"
+			android:selectAllOnFocus="true"
+			android:singleLine="true"
+			android:maxLength="64"
+			android:title="@string/prefs_authkey_subh4x"
+			android:summary="@string/prefs_authkey_subh4x" />
+
+		<EditTextPreference
+			android:defaultValue="5000"
+			android:inputType="number"
+			android:key="prefs_sockettimeout_subh4x"
+			android:maxLines="1"
+			android:maxLength="4"
+			android:selectAllOnFocus="true"
+			android:singleLine="true"
+			android:title="@string/prefs_sockettimeout" />
+	</PreferenceCategory>
+
+
+	<PreferenceCategory
+		android:title="Miscellaneous"
+		android:layout="@layout/preference_category">
+
+		<CheckBoxPreference
+			android:key="prefs_notifactive"
+			android:title="@string/prefs_notifactive"
+			android:summary="@string/prefs_notifactive_summary"
+			android:defaultValue="false"/>
+
+		<CheckBoxPreference
+			android:key="prefs_stickydrawer"
+			android:title="@string/prefs_stickydrawer"
+			android:summary="@string/prefs_stickydrawer_summary"
+			android:defaultValue="false"/>
+
+		<CheckBoxPreference
+			android:key="prefs_show_lockscreen"
+			android:title="@string/prefs_show_lockscreen"
+			android:summary="@string/prefs_show_lockscreen_summary"
+			android:defaultValue="false"/>
+
+		<CheckBoxPreference
+			android:key="prefs_autoconnect"
+			android:title="@string/prefs_autoconnect"
+			android:summary="@string/prefs_autoconnect_summary"
+			android:defaultValue="false"/>
+	</PreferenceCategory>
+
 	<PreferenceCategory
 		android:title="Not really settings lel"
 		android:layout="@layout/preference_category">

+ 2 - 2
app/src/app_k0di/version.properties

@@ -1,2 +1,2 @@
-#Thu Aug 13 19:59:10 CEST 2020
-VERSION_CODE=1800
+#Sat Oct 03 12:47:42 CEST 2020
+VERSION_CODE=1861

BIN
ass/scr0t1.png