mirror of
https://github.com/revanced/revanced-integrations.git
synced 2025-01-05 17:45:49 +01:00
start refactoring the integration impl
This commit is contained in:
parent
88a7838cd8
commit
b0d6658741
@ -0,0 +1,91 @@
|
||||
package fi.vanced.libraries.youtube.ads;
|
||||
|
||||
import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.currentVideoId;
|
||||
import static fi.vanced.libraries.youtube.ui.AdBlock.TAG;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import fi.vanced.libraries.youtube.player.ChannelModel;
|
||||
import fi.vanced.utils.requests.Requester;
|
||||
import fi.vanced.utils.requests.Route;
|
||||
|
||||
public class AdsRequester {
|
||||
private static final String YT_API_URL = "https://www.youtube.com/youtubei/v1";
|
||||
private static final String YT_API_KEY = "replaceMeWithTheYouTubeAPIKey";
|
||||
|
||||
public static void retrieveChannelDetails(View view, ImageView buttonIcon, Context context) {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(AdsRoutes.GET_CHANNEL_DETAILS, YT_API_KEY);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; utf-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(2 * 1000);
|
||||
|
||||
// TODO: Actually fetch the version
|
||||
String jsonInputString = "{\"context\": {\"client\": { \"clientName\": \"Android\", \"clientVersion\": \"16.49.37\" } }, \"videoId\": \"" + currentVideoId + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = getJSONObject(connection);
|
||||
JSONObject videoInfo = json.getJSONObject("videoDetails");
|
||||
ChannelModel channelModel = new ChannelModel(videoInfo.getString("author"), videoInfo.getString("channelId"));
|
||||
if (debug) {
|
||||
Log.d(TAG, "channelId " + channelModel.getChannelId() + " fetched for author " + channelModel.getAuthor());
|
||||
}
|
||||
|
||||
boolean success = VideoAds.addToWhitelist(context, channelModel.getAuthor(), channelModel.getChannelId());
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (success) {
|
||||
buttonIcon.setEnabled(true);
|
||||
Toast.makeText(context, "Channel " + channelModel.getAuthor() + " whitelisted", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else {
|
||||
buttonIcon.setEnabled(false);
|
||||
Toast.makeText(context, "Channel " + channelModel.getAuthor() + " failed to whitelist", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
view.setEnabled(true);
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (debug) {
|
||||
Log.d(TAG, "player fetch response was " + connection.getResponseCode());
|
||||
}
|
||||
|
||||
buttonIcon.setEnabled(false);
|
||||
view.setEnabled(true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to fetch channelId", ex);
|
||||
view.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
// helpers
|
||||
|
||||
private static HttpURLConnection getConnectionFromRoute(Route route, String... params) throws IOException {
|
||||
return Requester.getConnectionFromRoute(YT_API_URL, route, params);
|
||||
}
|
||||
|
||||
private static JSONObject getJSONObject(HttpURLConnection connection) throws Exception {
|
||||
return Requester.getJSONObject(connection);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package fi.vanced.libraries.youtube.ads;
|
||||
|
||||
import static fi.vanced.utils.requests.Route.Method.GET;
|
||||
|
||||
import fi.vanced.utils.requests.Route;
|
||||
|
||||
public class AdsRoutes {
|
||||
public static final Route GET_CHANNEL_DETAILS = new Route(GET, "player?key={api_key}");
|
||||
|
||||
private AdsRoutes() {}
|
||||
}
|
@ -4,7 +4,6 @@ import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.channelName;
|
||||
import static fi.vanced.libraries.youtube.ui.SlimButtonContainer.adBlockButton;
|
||||
import static fi.vanced.utils.VancedUtils.getPreferences;
|
||||
import static fi.vanced.utils.VancedUtils.parseJson;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
@ -12,12 +11,7 @@ import android.util.Log;
|
||||
|
||||
import com.google.android.apps.youtube.app.YouTubeTikTokRoot_Application;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
@ -55,63 +49,6 @@ public class VideoAds {
|
||||
}
|
||||
}
|
||||
|
||||
// Call to this needs to be injected in YT code (CURRENTLY NOT USED)
|
||||
public static void newVideoLoaded(String videoId) {
|
||||
if (debug) {
|
||||
Log.d(TAG, "newVideoLoaded - " + videoId);
|
||||
}
|
||||
|
||||
try {
|
||||
if (fetchThread != null && fetchThread.getState() != Thread.State.TERMINATED) {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Interrupting the thread. Current state " + fetchThread.getState());
|
||||
}
|
||||
fetchThread.interrupt();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Error in the fetch thread", ex);
|
||||
}
|
||||
|
||||
fetchThread = new Thread(() -> {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Fetching channelId for " + videoId);
|
||||
}
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(YT_API_URL + "/player?key=" + YT_API_KEY).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; utf-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(2 * 1000);
|
||||
|
||||
// TODO: Actually fetch the version
|
||||
String jsonInputString = "{\"context\": {\"client\": { \"clientName\": \"Android\", \"clientVersion\": \"16.49.37\" } }, \"videoId\": \"" + videoId + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes("utf-8");
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = new JSONObject(parseJson(connection));
|
||||
JSONObject videoInfo = json.getJSONObject("videoDetails");
|
||||
ChannelModel channelModel = new ChannelModel(videoInfo.getString("author"), videoInfo.getString("channelId"));
|
||||
if (debug) {
|
||||
Log.d(TAG, "channelId " + channelModel.getChannelId() + " fetched for author " + channelModel.getAuthor());
|
||||
}
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "player fetch response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to fetch channelId", ex);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
fetchThread.start();
|
||||
}
|
||||
|
||||
public static boolean getShouldShowAds() {
|
||||
if (!isEnabled) return false;
|
||||
|
||||
|
@ -4,19 +4,13 @@ import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.ryd.RYDSettings.PREFERENCES_KEY_USERID;
|
||||
import static fi.vanced.libraries.youtube.ryd.RYDSettings.PREFERENCES_NAME;
|
||||
import static fi.vanced.utils.VancedUtils.getPreferences;
|
||||
import static fi.vanced.utils.VancedUtils.parseJson;
|
||||
import static fi.vanced.utils.VancedUtils.randomString;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import fi.vanced.libraries.youtube.ryd.requests.RYDRequester;
|
||||
|
||||
public class Registration {
|
||||
private static final String TAG = "VI - RYD - Registration";
|
||||
@ -50,7 +44,7 @@ public class Registration {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
private void saveUserId(String userId) {
|
||||
public void saveUserId(String userId) {
|
||||
try {
|
||||
if (this.context == null) throw new Exception("Unable to save userId because context was null");
|
||||
|
||||
@ -64,87 +58,10 @@ public class Registration {
|
||||
}
|
||||
|
||||
private String register() {
|
||||
try {
|
||||
// Generate a new userId
|
||||
String userId = randomString(36);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to register the following userId: " + userId);
|
||||
}
|
||||
|
||||
// Get the registration challenge
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(ReturnYouTubeDislikes.RYD_API_URL + "/puzzle/registration?userId=" + userId).openConnection();
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
connection.setConnectTimeout(5 * 1000);
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = new JSONObject(parseJson(connection));
|
||||
String challenge = json.getString("challenge");
|
||||
int difficulty = json.getInt("difficulty");
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration challenge - " + challenge + " with difficulty of " + difficulty);
|
||||
}
|
||||
|
||||
// Solve the puzzle
|
||||
String solution = Utils.solvePuzzle(challenge, difficulty);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration confirmation solution is " + solution);
|
||||
}
|
||||
|
||||
return confirmRegistration(userId, solution);
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Registration response was " + connection.getResponseCode());
|
||||
}
|
||||
String userId = randomString(36);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to register the following userId: " + userId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to register userId", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String confirmRegistration(String userId, String solution) {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to confirm registration for the following userId: " + userId + " with solution: " + solution);
|
||||
}
|
||||
|
||||
// Confirm registration
|
||||
HttpURLConnection confirmationCon = (HttpURLConnection) new URL(ReturnYouTubeDislikes.RYD_API_URL + "/puzzle/registration?userId=" + userId).openConnection();
|
||||
confirmationCon.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
confirmationCon.setRequestMethod("POST");
|
||||
confirmationCon.setRequestProperty("Content-Type", "application/json");
|
||||
confirmationCon.setRequestProperty("Accept", "application/json");
|
||||
confirmationCon.setDoOutput(true);
|
||||
confirmationCon.setConnectTimeout(5 * 1000);
|
||||
|
||||
String jsonInputString = "{\"solution\": \"" + solution + "\"}";
|
||||
try(OutputStream os = confirmationCon.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (confirmationCon.getResponseCode() == 200) {
|
||||
String result = parseJson(confirmationCon);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration confirmation result was " + result);
|
||||
}
|
||||
|
||||
if (result.equalsIgnoreCase("true")) {
|
||||
saveUserId(userId);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration was successful for user " + userId);
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Registration confirmation response was " + confirmationCon.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to confirm registration", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
return RYDRequester.register(userId, this);
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,14 @@ package fi.vanced.libraries.youtube.ryd;
|
||||
|
||||
import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.currentVideoId;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.dislikeCount;
|
||||
import static fi.vanced.libraries.youtube.ryd.RYDSettings.PREFERENCES_KEY_RYD_ENABLED;
|
||||
import static fi.vanced.libraries.youtube.ryd.RYDSettings.PREFERENCES_NAME;
|
||||
import static fi.vanced.utils.VancedUtils.getIdentifier;
|
||||
import static fi.vanced.utils.VancedUtils.parseJson;
|
||||
|
||||
import android.content.Context;
|
||||
import android.icu.text.CompactDecimalFormat;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
@ -19,20 +17,14 @@ import android.widget.Toast;
|
||||
|
||||
import com.google.android.apps.youtube.app.YouTubeTikTokRoot_Application;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.dislikeCount;
|
||||
|
||||
import fi.vanced.libraries.youtube.ryd.requests.RYDRequester;
|
||||
import fi.vanced.utils.SharedPrefUtils;
|
||||
|
||||
public class ReturnYouTubeDislikes {
|
||||
public static final String RYD_API_URL = "https://returnyoutubedislikeapi.com";
|
||||
public static boolean isEnabled;
|
||||
private static final String TAG = "VI - RYD";
|
||||
public static final String TAG = "VI - RYD";
|
||||
private static View _dislikeView = null;
|
||||
private static Thread _dislikeFetchThread = null;
|
||||
private static Thread _votingThread = null;
|
||||
@ -96,39 +88,7 @@ public class ReturnYouTubeDislikes {
|
||||
Log.e(TAG, "Error in the dislike fetch thread", ex);
|
||||
}
|
||||
|
||||
_dislikeFetchThread = new Thread(() -> {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Fetching dislikes for " + videoId);
|
||||
}
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(RYD_API_URL + "/votes?videoId=" + videoId).openConnection();
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
connection.setConnectTimeout(5 * 1000);
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = new JSONObject(parseJson(connection));
|
||||
dislikeCount = json.getInt("dislikes");
|
||||
if (debug) {
|
||||
Log.d(TAG, "dislikes fetched - " + dislikeCount);
|
||||
}
|
||||
|
||||
// Set the dislikes
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable () {
|
||||
@Override
|
||||
public void run () {
|
||||
trySetDislikes(formatDislikes(dislikeCount));
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "dislikes fetch response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
dislikeCount = null;
|
||||
Log.e(TAG, "Failed to fetch dislikes", ex);
|
||||
return;
|
||||
}
|
||||
});
|
||||
_dislikeFetchThread = new Thread(() -> RYDRequester.fetchDislikes(videoId));
|
||||
_dislikeFetchThread.start();
|
||||
}
|
||||
|
||||
@ -211,7 +171,7 @@ public class ReturnYouTubeDislikes {
|
||||
return originalText;
|
||||
}
|
||||
|
||||
private static void trySetDislikes(String dislikeCount) {
|
||||
public static void trySetDislikes(String dislikeCount) {
|
||||
if (!isEnabled) return;
|
||||
|
||||
try {
|
||||
@ -345,7 +305,7 @@ public class ReturnYouTubeDislikes {
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatDislikes(int dislikes) {
|
||||
public static String formatDislikes(int dislikes) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && compactNumberFormatter != null) {
|
||||
final String formatted = compactNumberFormatter.format(dislikes);
|
||||
if (debug) {
|
||||
|
@ -1,13 +1,14 @@
|
||||
package fi.vanced.libraries.youtube.ryd;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class Utils {
|
||||
private static final String TAG = "VI - RYD - Utils";
|
||||
|
||||
static String solvePuzzle(String challenge, int difficulty) {
|
||||
public static String solvePuzzle(String challenge, int difficulty) {
|
||||
byte[] decodedChallenge = Base64.decode(challenge, Base64.NO_WRAP);
|
||||
|
||||
byte[] buffer = new byte[20];
|
||||
|
@ -1,17 +1,11 @@
|
||||
package fi.vanced.libraries.youtube.ryd;
|
||||
|
||||
import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.utils.VancedUtils.parseJson;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import fi.vanced.libraries.youtube.ryd.requests.RYDRequester;
|
||||
|
||||
public class Voting {
|
||||
private static final String TAG = "VI - RYD - Voting";
|
||||
@ -25,96 +19,10 @@ public class Voting {
|
||||
}
|
||||
|
||||
public boolean sendVote(String videoId, int vote) {
|
||||
try {
|
||||
String userId = registration.getUserId();
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to vote the following video: " + videoId + " with vote " + vote + " and userId: " + userId);
|
||||
}
|
||||
|
||||
// Send the vote
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(ReturnYouTubeDislikes.RYD_API_URL + "/interact/vote").openConnection();
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(5 * 1000);
|
||||
String voteJsonString = "{\"userId\": \"" + userId + "\", \"videoId\": \"" + videoId + "\", \"value\": \"" + vote + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = voteJsonString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = new JSONObject(parseJson(connection));
|
||||
String challenge = json.getString("challenge");
|
||||
int difficulty = json.getInt("difficulty");
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote challenge - " + challenge + " with difficulty of " + difficulty);
|
||||
}
|
||||
|
||||
// Solve the puzzle
|
||||
String solution = Utils.solvePuzzle(challenge, difficulty);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote confirmation solution is " + solution);
|
||||
}
|
||||
|
||||
// Confirm vote
|
||||
return confirmVote(userId, videoId, solution);
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Vote response was " + connection.getResponseCode());
|
||||
}
|
||||
String userId = registration.getUserId();
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to vote the following video: " + videoId + " with vote " + vote + " and userId: " + userId);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to send vote", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean confirmVote(String userId, String videoId, String solution) {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to confirm vote for video: " + videoId + " with solution " + solution + " and userId: " + userId);
|
||||
}
|
||||
|
||||
// Confirm vote
|
||||
HttpURLConnection confirmationCon = (HttpURLConnection) new URL(ReturnYouTubeDislikes.RYD_API_URL + "/interact/confirmVote").openConnection();
|
||||
confirmationCon.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
confirmationCon.setRequestMethod("POST");
|
||||
confirmationCon.setRequestProperty("Content-Type", "application/json");
|
||||
confirmationCon.setRequestProperty("Accept", "application/json");
|
||||
confirmationCon.setDoOutput(true);
|
||||
confirmationCon.setConnectTimeout(5 * 1000);
|
||||
|
||||
String jsonInputString = "{\"userId\": \"" + userId + "\", \"videoId\": \"" + videoId + "\", \"solution\": \"" + solution + "\"}";
|
||||
try(OutputStream os = confirmationCon.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (confirmationCon.getResponseCode() == 200) {
|
||||
String result = parseJson(confirmationCon);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote confirmation result was " + result);
|
||||
}
|
||||
|
||||
if (result.equalsIgnoreCase("true")) {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote was successful for user " + userId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Vote confirmation response was " + confirmationCon.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to send vote", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
return RYDRequester.sendVote(videoId, userId, vote);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,221 @@
|
||||
package fi.vanced.libraries.youtube.ryd.requests;
|
||||
|
||||
import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.dislikeCount;
|
||||
import static fi.vanced.libraries.youtube.ryd.ReturnYouTubeDislikes.TAG;
|
||||
import static fi.vanced.utils.requests.Requester.parseJson;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import fi.vanced.libraries.youtube.ryd.Registration;
|
||||
import fi.vanced.libraries.youtube.ryd.ReturnYouTubeDislikes;
|
||||
import fi.vanced.libraries.youtube.ryd.Utils;
|
||||
import fi.vanced.utils.requests.Requester;
|
||||
import fi.vanced.utils.requests.Route;
|
||||
|
||||
public class RYDRequester {
|
||||
private static final String RYD_API_URL = "https://returnyoutubedislikeapi.com/";
|
||||
|
||||
private RYDRequester() {}
|
||||
|
||||
public static void fetchDislikes(String videoId) {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Fetching dislikes for " + videoId);
|
||||
}
|
||||
HttpURLConnection connection = getConnectionFromRoute(RYDRoutes.GET_DISLIKES, videoId);
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
connection.setConnectTimeout(5 * 1000);
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = getJSONObject(connection);
|
||||
dislikeCount = json.getInt("dislikes");
|
||||
if (debug) {
|
||||
Log.d(TAG, "dislikes fetched - " + dislikeCount);
|
||||
}
|
||||
|
||||
// Set the dislikes
|
||||
new Handler(Looper.getMainLooper()).post(() -> ReturnYouTubeDislikes.trySetDislikes(ReturnYouTubeDislikes.formatDislikes(dislikeCount)));
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "dislikes fetch response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
dislikeCount = null;
|
||||
Log.e(TAG, "Failed to fetch dislikes", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static String register(String userId, Registration registration) {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(RYDRoutes.GET_REGISTRATION, userId);
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
connection.setConnectTimeout(5 * 1000);
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = getJSONObject(connection);
|
||||
String challenge = json.getString("challenge");
|
||||
int difficulty = json.getInt("difficulty");
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration challenge - " + challenge + " with difficulty of " + difficulty);
|
||||
}
|
||||
|
||||
// Solve the puzzle
|
||||
String solution = Utils.solvePuzzle(challenge, difficulty);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration confirmation solution is " + solution);
|
||||
}
|
||||
|
||||
return confirmRegistration(userId, solution, registration);
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Registration response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex){
|
||||
Log.e(TAG, "Failed to register userId", ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String confirmRegistration(String userId, String solution, Registration registration) {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Trying to confirm registration for the following userId: " + userId + " with solution: " + solution);
|
||||
}
|
||||
|
||||
HttpURLConnection connection = getConnectionFromRoute(RYDRoutes.CONFIRM_REGISTRATION, userId);
|
||||
applyCommonRequestSettings(connection);
|
||||
|
||||
String jsonInputString = "{\"solution\": \"" + solution + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (connection.getResponseCode() == 200) {
|
||||
String result = parseJson(connection);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration confirmation result was " + result);
|
||||
}
|
||||
|
||||
if (result.equalsIgnoreCase("true")) {
|
||||
registration.saveUserId(userId);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Registration was successful for user " + userId);
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Registration confirmation response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to confirm registration", ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean sendVote(String videoId, String userId, int vote) {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(RYDRoutes.SEND_VOTE);
|
||||
applyCommonRequestSettings(connection);
|
||||
|
||||
String voteJsonString = "{\"userId\": \"" + userId + "\", \"videoId\": \"" + videoId + "\", \"value\": \"" + vote + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = voteJsonString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = getJSONObject(connection);
|
||||
String challenge = json.getString("challenge");
|
||||
int difficulty = json.getInt("difficulty");
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote challenge - " + challenge + " with difficulty of " + difficulty);
|
||||
}
|
||||
|
||||
// Solve the puzzle
|
||||
String solution = Utils.solvePuzzle(challenge, difficulty);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote confirmation solution is " + solution);
|
||||
}
|
||||
|
||||
// Confirm vote
|
||||
return confirmVote(videoId, userId, solution);
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Vote response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to send vote", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean confirmVote(String videoId, String userId, String solution) {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(RYDRoutes.CONFIRM_VOTE);
|
||||
applyCommonRequestSettings(connection);
|
||||
|
||||
String jsonInputString = "{\"userId\": \"" + userId + "\", \"videoId\": \"" + videoId + "\", \"solution\": \"" + solution + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (connection.getResponseCode() == 200) {
|
||||
String result = parseJson(connection);
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote confirmation result was " + result);
|
||||
}
|
||||
|
||||
if (result.equalsIgnoreCase("true")) {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Vote was successful for user " + userId);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (debug) {
|
||||
Log.d(TAG, "Vote confirmation response was " + connection.getResponseCode());
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to confirm vote", ex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// utils
|
||||
|
||||
private static void applyCommonRequestSettings(HttpURLConnection connection) throws Exception {
|
||||
connection.setRequestProperty("User-agent", System.getProperty("http.agent") + ";vanced");
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(5 * 1000);
|
||||
}
|
||||
|
||||
// helpers
|
||||
|
||||
private static HttpURLConnection getConnectionFromRoute(Route route, String... params) throws IOException {
|
||||
return Requester.getConnectionFromRoute(RYD_API_URL, route, params);
|
||||
}
|
||||
|
||||
private static JSONObject getJSONObject(HttpURLConnection connection) throws Exception {
|
||||
return Requester.getJSONObject(connection);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package fi.vanced.libraries.youtube.ryd.requests;
|
||||
|
||||
import static fi.vanced.utils.requests.Route.Method.GET;
|
||||
import static fi.vanced.utils.requests.Route.Method.POST;
|
||||
|
||||
import fi.vanced.utils.requests.Route;
|
||||
|
||||
public class RYDRoutes {
|
||||
public static final Route SEND_VOTE = new Route(POST,"interact/vote");
|
||||
public static final Route CONFIRM_VOTE = new Route(POST,"interact/confirmVote");
|
||||
public static final Route GET_DISLIKES = new Route(GET, "votes?videoId={video_id}");
|
||||
public static final Route GET_REGISTRATION = new Route(GET, "puzzle/registration?userId={user_id}");
|
||||
public static final Route CONFIRM_REGISTRATION = new Route(POST,"puzzle/registration?userId={user_id}");
|
||||
|
||||
private RYDRoutes() {}
|
||||
}
|
@ -1,36 +1,23 @@
|
||||
package fi.vanced.libraries.youtube.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.ads.VideoAds.getShouldShowAds;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.currentVideoId;
|
||||
import static fi.vanced.utils.VancedUtils.parseJson;
|
||||
import static pl.jakubweg.StringRef.str;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import fi.vanced.libraries.youtube.ads.AdsRequester;
|
||||
import fi.vanced.libraries.youtube.ads.VideoAds;
|
||||
import fi.vanced.libraries.youtube.player.ChannelModel;
|
||||
import fi.vanced.libraries.youtube.player.VideoInformation;
|
||||
import fi.vanced.utils.SharedPrefUtils;
|
||||
import fi.vanced.utils.VancedUtils;
|
||||
|
||||
public class AdBlock extends SlimButton {
|
||||
private static final String TAG = "VI - AdBlock - Button";
|
||||
private static final String YT_API_URL = "https://www.youtube.com/youtubei/v1";
|
||||
private static final String YT_API_KEY = "replaceMeWithTheYouTubeAPIKey";
|
||||
public static final String TAG = "VI - AdBlock - Button";
|
||||
|
||||
public AdBlock(Context context, ViewGroup container) {
|
||||
super(context, container, SlimButton.SLIM_METADATA_BUTTON_ID, SharedPrefUtils.getBoolean(context, "youtube", "vanced_videoadwhitelisting_enabled", false));
|
||||
@ -60,7 +47,7 @@ public class AdBlock extends SlimButton {
|
||||
}
|
||||
//this.button_icon.setEnabled(!this.button_icon.isEnabled());
|
||||
|
||||
addToWhiteList(this.view, this.button_icon);
|
||||
addToWhiteList();
|
||||
}
|
||||
|
||||
private void removeFromWhitelist() {
|
||||
@ -76,61 +63,12 @@ public class AdBlock extends SlimButton {
|
||||
this.view.setEnabled(true);
|
||||
}
|
||||
|
||||
private void addToWhiteList(View view, ImageView buttonIcon) {
|
||||
private void addToWhiteList() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
if (debug) {
|
||||
Log.d(TAG, "Fetching channelId for " + currentVideoId);
|
||||
}
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(YT_API_URL + "/player?key=" + YT_API_KEY).openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json; utf-8");
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
connection.setDoOutput(true);
|
||||
connection.setConnectTimeout(2 * 1000);
|
||||
|
||||
// TODO: Actually fetch the version
|
||||
String jsonInputString = "{\"context\": {\"client\": { \"clientName\": \"Android\", \"clientVersion\": \"16.49.37\" } }, \"videoId\": \"" + currentVideoId + "\"}";
|
||||
try(OutputStream os = connection.getOutputStream()) {
|
||||
byte[] input = jsonInputString.getBytes("utf-8");
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
if (connection.getResponseCode() == 200) {
|
||||
JSONObject json = new JSONObject(parseJson(connection));
|
||||
JSONObject videoInfo = json.getJSONObject("videoDetails");
|
||||
ChannelModel channelModel = new ChannelModel(videoInfo.getString("author"), videoInfo.getString("channelId"));
|
||||
if (debug) {
|
||||
Log.d(TAG, "channelId " + channelModel.getChannelId() + " fetched for author " + channelModel.getAuthor());
|
||||
}
|
||||
|
||||
boolean success = VideoAds.addToWhitelist(this.context, channelModel.getAuthor(), channelModel.getChannelId());
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
if (success) {
|
||||
buttonIcon.setEnabled(true);
|
||||
Toast.makeText(context, "Channel " + channelModel.getAuthor() + " whitelisted", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
else {
|
||||
buttonIcon.setEnabled(false);
|
||||
Toast.makeText(context, "Channel " + channelModel.getAuthor() + " failed to whitelist", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
view.setEnabled(true);
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (debug) {
|
||||
Log.d(TAG, "player fetch response was " + connection.getResponseCode());
|
||||
}
|
||||
|
||||
buttonIcon.setEnabled(false);
|
||||
this.view.setEnabled(true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.e(TAG, "Failed to fetch channelId", ex);
|
||||
this.view.setEnabled(true);
|
||||
return;
|
||||
if (debug) {
|
||||
Log.d(TAG, "Fetching channelId for " + currentVideoId);
|
||||
}
|
||||
AdsRequester.retrieveChannelDetails(this.view, this.button_icon, this.context);
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
package fi.vanced.libraries.youtube.whitelisting;
|
||||
|
||||
import static fi.razerman.youtube.XGlobals.debug;
|
||||
import static fi.vanced.libraries.youtube.player.VideoInformation.channelName;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.apps.youtube.app.YouTubeTikTokRoot_Application;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import fi.vanced.libraries.youtube.player.ChannelModel;
|
||||
import fi.vanced.utils.ObjectSerializer;
|
||||
import fi.vanced.utils.SharedPrefUtils;
|
||||
import fi.vanced.utils.VancedUtils;
|
||||
|
||||
public class Whitelist {
|
||||
private static final String TAG = "VI - Whitelisting";
|
||||
private static final Map<WhitelistType, List<ChannelModel>> whitelistMap = parseWhitelist(YouTubeTikTokRoot_Application.getAppContext());
|
||||
private static final Map<WhitelistType, Boolean> enabledMap = parseEnabledMap(YouTubeTikTokRoot_Application.getAppContext());
|
||||
|
||||
private Whitelist() {}
|
||||
|
||||
public static boolean shouldShowAds() {
|
||||
return isWhitelisted(WhitelistType.ADS);
|
||||
}
|
||||
|
||||
public static boolean shouldShowSegments() {
|
||||
return !isWhitelisted(WhitelistType.SPONSORBLOCK);
|
||||
}
|
||||
|
||||
private static Map<WhitelistType, List<ChannelModel>> parseWhitelist(Context context) {
|
||||
if (context == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
WhitelistType[] whitelistTypes = WhitelistType.values();
|
||||
Map<WhitelistType, List<ChannelModel>> whitelistMap = new HashMap<>(whitelistTypes.length);
|
||||
|
||||
for (WhitelistType whitelistType : whitelistTypes) {
|
||||
SharedPreferences preferences = VancedUtils.getPreferences(context, whitelistType.getPreferencesName());
|
||||
String serializedChannels = preferences.getString("channels", null);
|
||||
if (serializedChannels == null) {
|
||||
if (debug) {
|
||||
Log.d(TAG, String.format("channels string was null for %s whitelisting", whitelistType));
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
try {
|
||||
List<ChannelModel> deserializedChannels = (List<ChannelModel>) ObjectSerializer.deserialize(serializedChannels);
|
||||
if (debug) {
|
||||
Log.d(TAG, serializedChannels);
|
||||
for (ChannelModel channel : deserializedChannels) {
|
||||
Log.d(TAG, String.format("Whitelisted channel %s (%s) for type %s", channel.getAuthor(), channel.getChannelId(), whitelistType));
|
||||
}
|
||||
}
|
||||
whitelistMap.put(whitelistType, deserializedChannels);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return whitelistMap;
|
||||
}
|
||||
|
||||
private static Map<WhitelistType, Boolean> parseEnabledMap(Context context) {
|
||||
WhitelistType[] whitelistTypes = WhitelistType.values();
|
||||
Map<WhitelistType, Boolean> enabledMap = new HashMap<>(whitelistTypes.length);
|
||||
for (WhitelistType whitelistType : whitelistTypes) {
|
||||
enabledMap.put(whitelistType, SharedPrefUtils.getBoolean(context, "youtube", whitelistType.getPreferenceEnabledName()));
|
||||
}
|
||||
return enabledMap;
|
||||
}
|
||||
|
||||
private static boolean isWhitelisted(WhitelistType whitelistType) {
|
||||
boolean isEnabled = enabledMap.get(whitelistType);
|
||||
if (!isEnabled) {
|
||||
return false;
|
||||
}
|
||||
if (channelName == null || channelName.trim().isEmpty()) {
|
||||
if (debug) {
|
||||
Log.d(TAG, String.format("Can't check whitelist status for %s because channel name was missing", whitelistType));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
List<ChannelModel> whitelistedChannels = whitelistMap.get(whitelistType);
|
||||
for (ChannelModel channel : whitelistedChannels) {
|
||||
if (channel.getAuthor().equals(channelName)) {
|
||||
if (debug) {
|
||||
Log.d(TAG, String.format("Whitelist for channel %s for type %s", channelName, whitelistType));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package fi.vanced.libraries.youtube.whitelisting;
|
||||
|
||||
public enum WhitelistType {
|
||||
ADS("vanced_whitelist_ads_enabled"),
|
||||
SPONSORBLOCK("vanced_whitelist_sb_enabled");
|
||||
|
||||
private final String preferencesName;
|
||||
private final String preferenceEnabledName;
|
||||
|
||||
WhitelistType(String preferenceEnabledName) {
|
||||
this.preferencesName = "whitelist_" + name();
|
||||
this.preferenceEnabledName = preferenceEnabledName;
|
||||
}
|
||||
|
||||
public String getPreferencesName() {
|
||||
return preferencesName;
|
||||
}
|
||||
|
||||
public String getPreferenceEnabledName() {
|
||||
return preferenceEnabledName;
|
||||
}
|
||||
}
|
@ -5,32 +5,17 @@ import android.content.SharedPreferences;
|
||||
|
||||
import com.google.android.apps.youtube.app.YouTubeTikTokRoot_Application;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class VancedUtils {
|
||||
|
||||
private VancedUtils() {}
|
||||
|
||||
public static SharedPreferences getPreferences(Context context, String preferencesName) {
|
||||
if (context == null) return null;
|
||||
return context.getSharedPreferences(preferencesName, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static String parseJson(HttpURLConnection connection) throws IOException {
|
||||
StringBuilder jsonBuilder = new StringBuilder();
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
jsonBuilder.append(line);
|
||||
}
|
||||
inputStream.close();
|
||||
return jsonBuilder.toString();
|
||||
}
|
||||
|
||||
public static int getIdentifier(String name, String defType) {
|
||||
Context context = YouTubeTikTokRoot_Application.getAppContext();
|
||||
return context.getResources().getIdentifier(name, defType, context.getPackageName());
|
||||
@ -46,4 +31,13 @@ public class VancedUtils {
|
||||
sb.append(AB.charAt(rnd.nextInt(AB.length())));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static int countMatches(CharSequence seq, char c) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < seq.length(); i++) {
|
||||
if (seq.charAt(i) == c)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
48
app/src/main/java/fi/vanced/utils/requests/Requester.java
Normal file
48
app/src/main/java/fi/vanced/utils/requests/Requester.java
Normal file
@ -0,0 +1,48 @@
|
||||
package fi.vanced.utils.requests;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
public class Requester {
|
||||
private Requester() {}
|
||||
|
||||
public static HttpURLConnection getConnectionFromRoute(String apiUrl, Route route, String... params) throws IOException {
|
||||
String url = apiUrl + route.compile(params).getCompiledRoute();
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setRequestMethod(route.getMethod().name());
|
||||
return connection;
|
||||
}
|
||||
|
||||
public static String parseJson(HttpURLConnection connection) throws IOException {
|
||||
StringBuilder jsonBuilder = new StringBuilder();
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
jsonBuilder.append(line);
|
||||
}
|
||||
inputStream.close();
|
||||
return jsonBuilder.toString();
|
||||
}
|
||||
|
||||
public static JSONObject getJSONObject(HttpURLConnection connection) throws Exception {
|
||||
return new JSONObject(parseJsonAndDisconnect(connection));
|
||||
}
|
||||
|
||||
public static JSONArray getJSONArray(HttpURLConnection connection) throws Exception {
|
||||
return new JSONArray(parseJsonAndDisconnect(connection));
|
||||
}
|
||||
|
||||
private static String parseJsonAndDisconnect(HttpURLConnection connection) throws IOException {
|
||||
String json = parseJson(connection);
|
||||
connection.disconnect();
|
||||
return json;
|
||||
}
|
||||
}
|
59
app/src/main/java/fi/vanced/utils/requests/Route.java
Normal file
59
app/src/main/java/fi/vanced/utils/requests/Route.java
Normal file
@ -0,0 +1,59 @@
|
||||
package fi.vanced.utils.requests;
|
||||
|
||||
import fi.vanced.utils.VancedUtils;
|
||||
|
||||
public class Route {
|
||||
private final String route;
|
||||
private final Route.Method method;
|
||||
private final int paramCount;
|
||||
|
||||
public Route(Route.Method method, String route) {
|
||||
this.method = method;
|
||||
this.route = route;
|
||||
this.paramCount = VancedUtils.countMatches(route, '{');
|
||||
|
||||
if (paramCount != VancedUtils.countMatches(route, '}'))
|
||||
throw new IllegalArgumentException("Not enough parameters");
|
||||
}
|
||||
|
||||
public Route.Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public Route.CompiledRoute compile(String... params) {
|
||||
if (params.length != paramCount)
|
||||
throw new IllegalArgumentException("Error compiling route [" + route + "], incorrect amount of parameters provided. " +
|
||||
"Expected: " + paramCount + ", provided: " + params.length);
|
||||
|
||||
StringBuilder compiledRoute = new StringBuilder(route);
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
int paramStart = compiledRoute.indexOf("{");
|
||||
int paramEnd = compiledRoute.indexOf("}");
|
||||
compiledRoute.replace(paramStart, paramEnd + 1, params[i]);
|
||||
}
|
||||
return new Route.CompiledRoute(this, compiledRoute.toString());
|
||||
}
|
||||
|
||||
public static class CompiledRoute {
|
||||
private final Route baseRoute;
|
||||
private final String compiledRoute;
|
||||
|
||||
private CompiledRoute(Route baseRoute, String compiledRoute) {
|
||||
this.baseRoute = baseRoute;
|
||||
this.compiledRoute = compiledRoute;
|
||||
}
|
||||
|
||||
public String getCompiledRoute() {
|
||||
return compiledRoute;
|
||||
}
|
||||
|
||||
public Route.Method getMethod() {
|
||||
return baseRoute.method;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Method {
|
||||
GET,
|
||||
POST
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package pl.jakubweg;
|
||||
|
||||
import static pl.jakubweg.SponsorBlockSettings.skippedSegments;
|
||||
import static pl.jakubweg.SponsorBlockSettings.skippedTime;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
@ -23,10 +26,7 @@ import java.util.TimerTask;
|
||||
|
||||
import fi.vanced.libraries.youtube.player.VideoInformation;
|
||||
import pl.jakubweg.objects.SponsorSegment;
|
||||
import pl.jakubweg.requests.Requester;
|
||||
|
||||
import static pl.jakubweg.SponsorBlockSettings.skippedSegments;
|
||||
import static pl.jakubweg.SponsorBlockSettings.skippedTime;
|
||||
import pl.jakubweg.requests.SBRequester;
|
||||
|
||||
@SuppressLint({"LongLogTag"})
|
||||
public class PlayerController {
|
||||
@ -123,7 +123,7 @@ public class PlayerController {
|
||||
}
|
||||
|
||||
public static void executeDownloadSegments(String videoId) {
|
||||
SponsorSegment[] segments = Requester.getSegments(videoId);
|
||||
SponsorSegment[] segments = SBRequester.getSegments(videoId);
|
||||
Arrays.sort(segments);
|
||||
|
||||
if (VERBOSE)
|
||||
@ -281,7 +281,7 @@ public class PlayerController {
|
||||
segment.category != SponsorBlockSettings.SegmentInfo.UNSUBMITTED &&
|
||||
millis - segment.start < 2000) {
|
||||
// Only skips from the start should count as a view
|
||||
Requester.sendViewCountRequest(segment);
|
||||
SBRequester.sendViewCountRequest(segment);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ import android.widget.Toast;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import pl.jakubweg.requests.Requester;
|
||||
import pl.jakubweg.requests.SBRequester;
|
||||
|
||||
@SuppressWarnings({"unused", "deprecation"}) // injected
|
||||
public class SponsorBlockPreferenceFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
@ -197,7 +197,7 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment implement
|
||||
category.addPreference(preference);
|
||||
preference.setTitle(str("stats_loading"));
|
||||
|
||||
Requester.retrieveUserStats(category, preference);
|
||||
SBRequester.retrieveUserStats(category, preference);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ import static pl.jakubweg.SponsorBlockSettings.skippedSegments;
|
||||
import static pl.jakubweg.SponsorBlockSettings.skippedTime;
|
||||
import static pl.jakubweg.SponsorBlockSettings.uuid;
|
||||
import static pl.jakubweg.StringRef.str;
|
||||
import static pl.jakubweg.requests.Requester.voteForSegment;
|
||||
import static pl.jakubweg.requests.SBRequester.voteForSegment;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlertDialog;
|
||||
@ -61,7 +61,7 @@ import java.util.TimeZone;
|
||||
|
||||
import pl.jakubweg.objects.SponsorSegment;
|
||||
import pl.jakubweg.objects.UserStats;
|
||||
import pl.jakubweg.requests.Requester;
|
||||
import pl.jakubweg.requests.SBRequester;
|
||||
|
||||
@SuppressWarnings({"LongLogTag"})
|
||||
public abstract class SponsorBlockUtils {
|
||||
@ -281,7 +281,7 @@ public abstract class SponsorBlockUtils {
|
||||
Log.e(TAG, "Unable to submit times, invalid parameters");
|
||||
return;
|
||||
}
|
||||
Requester.submitSegments(videoId, uuid, ((float) start) / 1000f, ((float) end) / 1000f, segmentType.key, toastRunnable);
|
||||
SBRequester.submitSegments(videoId, uuid, ((float) start) / 1000f, ((float) end) / 1000f, segmentType.key, toastRunnable);
|
||||
newSponsorSegmentEndMillis = newSponsorSegmentStartMillis = -1;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to submit segment", e);
|
||||
@ -485,15 +485,6 @@ public abstract class SponsorBlockUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static int countMatches(CharSequence seq, char c) {
|
||||
int count = 0;
|
||||
for (int i = 0; i < seq.length(); i++) {
|
||||
if (seq.charAt(i) == c)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static String formatColorString(int color) {
|
||||
return String.format("#%06X", color);
|
||||
}
|
||||
@ -514,7 +505,7 @@ public abstract class SponsorBlockUtils {
|
||||
preference.setText(userName);
|
||||
preference.setOnPreferenceChangeListener((preference1, newUsername) -> {
|
||||
appContext = new WeakReference<>(context.getApplicationContext());
|
||||
Requester.setUsername((String) newUsername, toastRunnable);
|
||||
SBRequester.setUsername((String) newUsername, toastRunnable);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
package pl.jakubweg.requests;
|
||||
|
||||
import static pl.jakubweg.requests.Route.Method.GET;
|
||||
import static pl.jakubweg.requests.Route.Method.POST;
|
||||
|
||||
import pl.jakubweg.SponsorBlockUtils;
|
||||
|
||||
public class Route {
|
||||
public static final Route GET_SEGMENTS = new Route(GET, "skipSegments?videoID={video_id}&categories={categories}");
|
||||
public static final Route VIEWED_SEGMENT = new Route(POST, "viewedVideoSponsorTime?UUID={segment_id}");
|
||||
public static final Route GET_USER_STATS = new Route(GET, "userInfo?userID={user_id}&values=[\"userName\", \"minutesSaved\", \"segmentCount\", \"viewCount\"]");
|
||||
public static final Route CHANGE_USERNAME = new Route(POST, "setUsername?userID={user_id}&username={username}");
|
||||
public static final Route SUBMIT_SEGMENTS = new Route(POST, "skipSegments?videoID={video_id}&userID={user_id}&startTime={start_time}&endTime={end_time}&category={category}");
|
||||
public static final Route VOTE_ON_SEGMENT_QUALITY = new Route(POST, "voteOnSponsorTime?UUID={segment_id}&userID={user_id}&type={type}");
|
||||
public static final Route VOTE_ON_SEGMENT_CATEGORY = new Route(POST, "voteOnSponsorTime?UUID={segment_id}&userID={user_id}&category={category}");
|
||||
|
||||
private final String route;
|
||||
private final Method method;
|
||||
private final int paramCount;
|
||||
|
||||
private Route(Method method, String route) {
|
||||
this.method = method;
|
||||
this.route = route;
|
||||
this.paramCount = SponsorBlockUtils.countMatches(route, '{');
|
||||
|
||||
if (paramCount != SponsorBlockUtils.countMatches(route, '}'))
|
||||
throw new IllegalArgumentException("Not enough parameters");
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public CompiledRoute compile(String... params) {
|
||||
if (params.length != paramCount)
|
||||
throw new IllegalArgumentException("Error compiling route [" + route + "], incorrect amount of parameters provided. " +
|
||||
"Expected: " + paramCount + ", provided: " + params.length);
|
||||
|
||||
StringBuilder compiledRoute = new StringBuilder(route);
|
||||
for (int i = 0; i < paramCount; i++) {
|
||||
int paramStart = compiledRoute.indexOf("{");
|
||||
int paramEnd = compiledRoute.indexOf("}");
|
||||
compiledRoute.replace(paramStart, paramEnd + 1, params[i]);
|
||||
}
|
||||
return new CompiledRoute(this, compiledRoute.toString());
|
||||
}
|
||||
|
||||
public static class CompiledRoute {
|
||||
private final Route baseRoute;
|
||||
private final String compiledRoute;
|
||||
|
||||
private CompiledRoute(Route baseRoute, String compiledRoute) {
|
||||
this.baseRoute = baseRoute;
|
||||
this.compiledRoute = compiledRoute;
|
||||
}
|
||||
|
||||
public String getCompiledRoute() {
|
||||
return compiledRoute;
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return baseRoute.method;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Method {
|
||||
GET,
|
||||
POST
|
||||
}
|
||||
}
|
@ -14,41 +14,39 @@ import android.widget.Toast;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import fi.vanced.utils.requests.Requester;
|
||||
import fi.vanced.utils.requests.Route;
|
||||
import pl.jakubweg.SponsorBlockSettings;
|
||||
import pl.jakubweg.SponsorBlockUtils;
|
||||
import pl.jakubweg.SponsorBlockUtils.VoteOption;
|
||||
import pl.jakubweg.objects.SponsorSegment;
|
||||
import pl.jakubweg.objects.UserStats;
|
||||
|
||||
public class Requester {
|
||||
private static final String SPONSORBLOCK_API_URL = "https://sponsor.ajay.app/api/";
|
||||
public class SBRequester {
|
||||
private static final String SPONSORLOCK_API_URL = "https://sponsor.ajay.app/api/";
|
||||
private static final String TIME_TEMPLATE = "%.3f";
|
||||
|
||||
private Requester() {}
|
||||
private SBRequester() {}
|
||||
|
||||
public static synchronized SponsorSegment[] getSegments(String videoId) {
|
||||
List<SponsorSegment> segments = new ArrayList<>();
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(Route.GET_SEGMENTS, videoId, SponsorBlockSettings.sponsorBlockUrlCategories);
|
||||
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.GET_SEGMENTS, videoId, SponsorBlockSettings.sponsorBlockUrlCategories);
|
||||
int responseCode = connection.getResponseCode();
|
||||
videoHasSegments = false;
|
||||
timeWithoutSegments = "";
|
||||
|
||||
if (responseCode == 200) {
|
||||
JSONArray responseArray = new JSONArray(parseJson(connection));
|
||||
JSONArray responseArray = Requester.getJSONArray(connection);
|
||||
int length = responseArray.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
JSONObject obj = ((JSONObject) responseArray.get(i));
|
||||
JSONObject obj = (JSONObject) responseArray.get(i);
|
||||
JSONArray segment = obj.getJSONArray("segment");
|
||||
long start = (long) (segment.getDouble(0) * 1000);
|
||||
long end = (long) (segment.getDouble(1) * 1000);
|
||||
@ -64,7 +62,6 @@ public class Requester {
|
||||
videoHasSegments = true;
|
||||
timeWithoutSegments = SponsorBlockUtils.getTimeWithoutSegments(segments.toArray(new SponsorSegment[0]));
|
||||
}
|
||||
connection.disconnect();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
@ -76,7 +73,7 @@ public class Requester {
|
||||
try {
|
||||
String start = String.format(Locale.US, TIME_TEMPLATE, startTime);
|
||||
String end = String.format(Locale.US, TIME_TEMPLATE, endTime);
|
||||
HttpURLConnection connection = getConnectionFromRoute(Route.SUBMIT_SEGMENTS, videoId, uuid, start, end, category);
|
||||
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.SUBMIT_SEGMENTS, videoId, uuid, start, end, category);
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
switch (responseCode) {
|
||||
@ -106,7 +103,7 @@ public class Requester {
|
||||
|
||||
public static void sendViewCountRequest(SponsorSegment segment) {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(Route.VIEWED_SEGMENT, segment.UUID);
|
||||
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.VIEWED_SEGMENT, segment.UUID);
|
||||
connection.disconnect();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
@ -123,8 +120,8 @@ public class Requester {
|
||||
Toast.makeText(context, str("vote_started"), Toast.LENGTH_SHORT).show();
|
||||
|
||||
HttpURLConnection connection = voteOption == VoteOption.CATEGORY_CHANGE
|
||||
? getConnectionFromRoute(Route.VOTE_ON_SEGMENT_CATEGORY, segmentUuid, uuid, args[0])
|
||||
: getConnectionFromRoute(Route.VOTE_ON_SEGMENT_QUALITY, segmentUuid, uuid, vote);
|
||||
? getConnectionFromRoute(SBRoutes.VOTE_ON_SEGMENT_CATEGORY, segmentUuid, uuid, args[0])
|
||||
: getConnectionFromRoute(SBRoutes.VOTE_ON_SEGMENT_QUALITY, segmentUuid, uuid, vote);
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
switch (responseCode) {
|
||||
@ -154,9 +151,7 @@ public class Requester {
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(Route.GET_USER_STATS, SponsorBlockSettings.uuid);
|
||||
JSONObject json = new JSONObject(parseJson(connection));
|
||||
connection.disconnect();
|
||||
JSONObject json = getJSONObject(SBRoutes.GET_USER_STATS, SponsorBlockSettings.uuid);
|
||||
UserStats stats = new UserStats(json.getString("userName"), json.getDouble("minutesSaved"), json.getInt("segmentCount"),
|
||||
json.getInt("viewCount"));
|
||||
SponsorBlockUtils.addUserStats(category, loadingPreference, stats);
|
||||
@ -169,7 +164,7 @@ public class Requester {
|
||||
|
||||
public static void setUsername(String username, Runnable toastRunnable) {
|
||||
try {
|
||||
HttpURLConnection connection = getConnectionFromRoute(Route.CHANGE_USERNAME, SponsorBlockSettings.uuid, username);
|
||||
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.CHANGE_USERNAME, SponsorBlockSettings.uuid, username);
|
||||
int responseCode = connection.getResponseCode();
|
||||
|
||||
if (responseCode == 200) {
|
||||
@ -187,21 +182,10 @@ public class Requester {
|
||||
}
|
||||
|
||||
private static HttpURLConnection getConnectionFromRoute(Route route, String... params) throws IOException {
|
||||
String url = SPONSORBLOCK_API_URL + route.compile(params).getCompiledRoute();
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
|
||||
connection.setRequestMethod(route.getMethod().name());
|
||||
return connection;
|
||||
return Requester.getConnectionFromRoute(SPONSORLOCK_API_URL, route, params);
|
||||
}
|
||||
|
||||
private static String parseJson(HttpURLConnection connection) throws IOException {
|
||||
StringBuilder jsonBuilder = new StringBuilder();
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
jsonBuilder.append(line);
|
||||
}
|
||||
inputStream.close();
|
||||
return jsonBuilder.toString();
|
||||
private static JSONObject getJSONObject(Route route, String... params) throws Exception {
|
||||
return Requester.getJSONObject(getConnectionFromRoute(route, params));
|
||||
}
|
||||
}
|
18
app/src/main/java/pl/jakubweg/requests/SBRoutes.java
Normal file
18
app/src/main/java/pl/jakubweg/requests/SBRoutes.java
Normal file
@ -0,0 +1,18 @@
|
||||
package pl.jakubweg.requests;
|
||||
|
||||
import static fi.vanced.utils.requests.Route.Method.GET;
|
||||
import static fi.vanced.utils.requests.Route.Method.POST;
|
||||
|
||||
import fi.vanced.utils.requests.Route;
|
||||
|
||||
public class SBRoutes {
|
||||
public static final Route GET_SEGMENTS = new Route(GET, "skipSegments?videoID={video_id}&categories={categories}");
|
||||
public static final Route VIEWED_SEGMENT = new Route(POST, "viewedVideoSponsorTime?UUID={segment_id}");
|
||||
public static final Route GET_USER_STATS = new Route(GET, "userInfo?userID={user_id}&values=[\"userName\", \"minutesSaved\", \"segmentCount\", \"viewCount\"]");
|
||||
public static final Route CHANGE_USERNAME = new Route(POST, "setUsername?userID={user_id}&username={username}");
|
||||
public static final Route SUBMIT_SEGMENTS = new Route(POST, "skipSegments?videoID={video_id}&userID={user_id}&startTime={start_time}&endTime={end_time}&category={category}");
|
||||
public static final Route VOTE_ON_SEGMENT_QUALITY = new Route(POST, "voteOnSponsorTime?UUID={segment_id}&userID={user_id}&type={type}");
|
||||
public static final Route VOTE_ON_SEGMENT_CATEGORY = new Route(POST, "voteOnSponsorTime?UUID={segment_id}&userID={user_id}&category={category}");
|
||||
|
||||
private SBRoutes() {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user