start refactoring the integration impl

This commit is contained in:
caneleex 2022-01-17 14:54:11 +01:00
parent 61b6c6a371
commit 5192d60af0
21 changed files with 658 additions and 511 deletions

View File

@ -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);
}
}

View File

@ -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() {}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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];

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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() {}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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;
}
}

View 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
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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;
});
}

View File

@ -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
}
}

View File

@ -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));
}
}

View 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() {}
}