Compare commits

...
35 Commits
Author SHA1 Message Date
gdlbo e5c407ed13 native check 2024-03-02 22:23:31 +03:00
Artur Skubei f185668e7e Merge branch 'main' into sponsorpost-votes 2024-03-02 21:50:08 +03:00
gdlbo f0246b722f Update NewsFeedFiltersUtils.java 2024-02-25 22:59:15 +03:00
gdlbo 803c2ffa40 Merge branch 'main' into sponsorpost-votes 2024-02-25 22:18:19 +03:00
gdlbo 51bbcb5305 Update NewsFeedFiltersUtils.java 2024-02-25 22:12:01 +03:00
gdlbo 60277d0d19 added some sponsorpost checks 2024-02-25 20:48:10 +03:00
gdlbo 36f4a348ca Update proguard-rules.pro 2024-02-25 20:44:15 +03:00
gdlbo 999f1ccd06 Improvement artist fetch
for caching, genius and lastfm
2024-02-25 20:12:39 +03:00
gdlbo 1f5efdb41e test 2024-02-25 15:10:44 +03:00
gdlbo 18c73d4e48 fixes 2024-02-22 17:06:23 +03:00
gdlbo 4341804732 added gzip for vkn api 2024-02-21 20:03:27 +03:00
gdlbo d7c1ce4b78 added support gzip for audio downloaders and catalogs 2024-02-21 19:29:09 +03:00
gdlbo 7a30e2aae6 Update VTVerifications.java 2024-02-21 19:10:03 +03:00
gdlbo 0194f5ede1 some gzip refactoring 2024-02-21 17:06:20 +03:00
gdlbo e5b5467b27 fixed force update verifs 2024-02-21 17:04:45 +03:00
gdlbo 982b2bb059 fixed auto updates 2024-02-21 16:58:47 +03:00
gdlbo bf6c72f2a8 added gzip support for updates 2024-02-21 16:10:57 +03:00
gdlbo 5214964e0f added gzip support for verifs 2024-02-21 16:03:35 +03:00
gdlbo ade17dd2cf Update SponsorPostFragment.java 2024-02-21 13:05:11 +03:00
gdlbo a14043c4f3 reduce responce weight 2024-02-20 17:12:37 +03:00
gdlbo 678774c44e Update SponsorPostFragment.java 2024-02-20 16:59:05 +03:00
gdlbo 58f80a5f54 Update SponsorPostFragment.java 2024-02-20 16:45:13 +03:00
gdlbo f6a2412014 Update SponsorPostFragment.java 2024-02-20 16:25:53 +03:00
gdlbo cf99b8a838 Merge branch 'main' into sponsorpost-votes 2024-02-20 14:50:47 +03:00
gdlbo baa3afc378 fix disabled sponsorpost 2024-02-20 01:57:07 +03:00
gdlbo dbdf5469f5 Update SponsorPostFragment.java 2024-02-20 01:41:30 +03:00
gdlbo 7fc51708f9 fixed all issues with voting 2024-02-20 01:19:57 +03:00
gdlbo 25cc4720f7 added vote dialog 2024-02-20 00:56:36 +03:00
gdlbo 00b1fa3cad added posts menu hooks 2024-02-20 00:39:16 +03:00
gdlbo 71edb4db24 Update AdMarkHolder.java 2024-02-19 23:28:41 +03:00
gdlbo cd6ed0f51f fixed parse bug 2024-02-19 23:16:55 +03:00
gdlbo c18ea2846f sponsorpost stats 2024-02-19 18:28:35 +03:00
gdlbo de9382cb50 Merge branch 'main' into sponsorpost-votes 2024-02-19 15:40:59 +03:00
gdlbo 9aa8a3d45c vote system
not working :(
2024-02-16 21:38:09 +03:00
gdlbo 9efccb37ad init 2024-02-16 03:02:58 +03:00
37 changed files with 888 additions and 372 deletions
+1 -1
View File
@@ -35,7 +35,7 @@
-optimizationpasses 5
-keepattributes SourceFile, LineNumberTable
-keep,allowoptimization class ru.vtosters.hooks.**, ru.vtosters.lite.utils.AndroidUtils, ru.vtosters.lite.utils.NetworkUtils, ru.vtosters.lite.utils.CrashReporter, ru.vtosters.lite.ui.activities.**, ru.vtosters.lite.services.**, ru.vtosters.lite.ui.fragments.**, ru.vtosters.lite.themes.**, ru.vtosters.lite.music.hook.**, ru.vtosters.lite.music.cache.injectors.**, ru.vtosters.lite.ui.wallpapers.NativeEffects, com.aefyr.tsg.g2.TelegramStickersService {
-keep,allowoptimization class ru.vtosters.hooks.**, ru.vtosters.sponsorpost.internal.Native, ru.vtosters.lite.utils.AndroidUtils, ru.vtosters.lite.utils.NetworkUtils, ru.vtosters.lite.utils.CrashReporter, ru.vtosters.lite.ui.activities.**, ru.vtosters.lite.services.**, ru.vtosters.lite.ui.fragments.**, ru.vtosters.lite.themes.**, ru.vtosters.lite.music.hook.**, ru.vtosters.lite.music.cache.injectors.**, ru.vtosters.lite.ui.wallpapers.NativeEffects, com.aefyr.tsg.g2.TelegramStickersService {
public <fields>;
public <methods>;
public <init>(...);
@@ -10,6 +10,7 @@ import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import com.facebook.soloader.SoLoader;
import ru.vtosters.sponsorpost.internal.Native;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -274,6 +275,7 @@ public final class MediaNative {
SoLoader.init(context2, false);
NativeLibLoader.loadLibrary("gnustl_shared");
NativeLibLoader.loadLibrary("vkchronicle");
Native.canVote = NativeLibLoader.loadLibrary("sponsorpost");
loadVKMediaLibs();
f17443d.notifyAll();
}
@@ -0,0 +1,106 @@
package com.vk.newsfeed.holders;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import com.vk.core.dialogs.alert.VkAlertDialog;
import com.vk.core.ui.themes.VKThemeHelper;
import com.vk.dto.newsfeed.entries.NewsEntry;
import com.vk.dto.newsfeed.entries.Post;
import com.vk.dto.newsfeed.entries.PromoPost;
import com.vk.extensions.ViewExtKt;
import com.vtosters.lite.R;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
import ru.vtosters.sponsorpost.internal.Native;
import ru.vtosters.sponsorpost.internal.VotesPreferences;
import ru.vtosters.sponsorpost.internal.VotesService;
import ru.vtosters.sponsorpost.utils.PostsPreferences;
public final class AdMarkHolder extends BaseNewsEntryHolder<NewsEntry> {
private final TextView F;
@SuppressLint("ResourceType")
public AdMarkHolder(ViewGroup viewGroup) {
super(R.layout.marked_as_ads, viewGroup);
View view = ((RecyclerView.ViewHolder) this).itemView;
this.F = ViewExtKt.a(view, R.id.text, (View.OnClickListener) null);
}
@SuppressLint("ResourceType")
public void b(NewsEntry newsEntry) { // onBind
String disclamer = null;
Drawable drawable = null;
int height = 0;
if (newsEntry instanceof Post) {
Post post = ((Post) newsEntry);
if (post.L1()) {
drawable = VKThemeHelper.a(R.drawable.marked_as_ads, R.attr.icon_tertiary);
int ownerId = post.b();
int postId = post.P1();
int date = post.K();
String text = post.getText();
if (PostsPreferences.isPostAd(ownerId, postId)) {
disclamer = "SponsorPost: Реклама";
if (Preferences.isValidSignature() && Native.canVote()) {
this.F.setOnClickListener(listener -> voteDialog(ownerId, postId, date, this.F.getContext()));
}
} else if (VotesPreferences.isPostAd(ownerId, postId)) {
disclamer = "SponsorPost: Возможно реклама";
if (Preferences.isValidSignature() && Native.canVote()) {
this.F.setOnClickListener(listener -> voteDialog(ownerId, postId, date, this.F.getContext()));
}
} else if (NewsFeedFiltersUtils.sponsorFilters(text)) {
disclamer = "SponsorPost: Заблокировано фильтрами";
this.F.setOnClickListener(listener -> AndroidUtils.sendToast("Заблокировано по выражению: " + NewsFeedFiltersUtils.sponsorFiltersBanWord(text)));
} else {
disclamer = m(R.string.sponsored_post_in_group);
}
height = e0().getDimensionPixelSize(R.dimen.newsfeed_ad_mark_post_height);
}
} else if (newsEntry instanceof PromoPost) {
PromoPost promoPost = (PromoPost) newsEntry;
if (!promoPost.E1().isEmpty()) {
height = e0().getDimensionPixelSize(R.dimen.newsfeed_ad_mark_promo_post_height);
disclamer = promoPost.E1();
}
}
this.F.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
this.F.setMinHeight(height);
this.F.setText(disclamer);
}
public static void voteDialog(int ownerId, int postId, int date, Context ctx) {
new VkAlertDialog.Builder(ctx)
.setTitle("SponsorPost")
.setMessage("Этот пост является рекламным?")
.setPositiveButton("Да", ((dialog, which) -> {
int resp = VotesService.ratePost(ownerId, postId, date, true).optInt("code");
if (resp == 201 || resp == 100) {
AndroidUtils.sendToast("Спасибо за голос!");
} else {
AndroidUtils.sendToast("Ваш голос уже учтен");
}
}))
.setNeutralButton("Нет", ((dialog, which) -> {
int resp = VotesService.ratePost(ownerId, postId, date, false).optInt("code");
if (resp == 201 || resp == 100) {
AndroidUtils.sendToast("Спасибо за голос!");
} else {
AndroidUtils.sendToast("Ваш голос уже учтен");
}
}))
.show();
}
}
@@ -11,13 +11,12 @@ import com.vk.discover.DiscoverItemDecorator;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.concurrent.VTExecutors;
import ru.vtosters.lite.utils.NetworkUtils;
import ru.vtosters.sponsorpost.internal.VotesPreferences;
import ru.vtosters.sponsorpost.internal.VotesService;
import ru.vtosters.sponsorpost.services.PostService;
import ru.vtosters.sponsorpost.utils.PostsPreferences;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.*;
import static java.lang.Long.MAX_VALUE;
import static ru.vtosters.hooks.other.Preferences.*;
@@ -102,8 +101,16 @@ public class NewsfeedHook {
public static void takeOwnerIdSponsorPost(int ownerid) {
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable()) {
VTExecutors.getIoScheduler().a(() -> {
List<Long> postIds = PostService.getPostIdsByOwnerId((long) ownerid, 0L);
PostsPreferences.saveGroupSpecifiedPosts(postIds, (long) ownerid);
if (PostsPreferences.isGroupAd(ownerid) || VotesPreferences.isGroupAd(ownerid)) {
if (VotesPreferences.isEnabled()) {
Map<String, List<String>> postIds = VotesService.getPostIdsByOwnerId((long) ownerid, 0L);
VotesPreferences.saveGroupSpecifiedPosts(postIds.get("vote"), (long) ownerid);
PostsPreferences.saveGroupSpecifiedPosts(postIds.get("prod"), (long) ownerid);
} else {
List<Long> postIds = PostService.getPostIdsByOwnerId((long) ownerid, 0L);
PostsPreferences.saveGroupSpecifiedPosts(postIds, (long) ownerid);
}
}
});
}
}
@@ -112,17 +119,28 @@ public class NewsfeedHook {
long ownerid = Long.parseLong(strArr[0].split("_")[0]);
long postId = Long.parseLong(strArr[0].split("_")[1]);
if (PostsPreferences.isPostAd(ownerid, postId)) {
if (PostsPreferences.isPostAd(ownerid, postId) || VotesPreferences.isPostAd(ownerid, postId)) {
return;
}
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable() && PostsPreferences.isGroupAd(ownerid)) {
if (NetworkUtils.isNetworkConnected() && PostsPreferences.isEnabled() && !Preferences.serverFeaturesDisable()) {
VTExecutors.getIoScheduler().a(() -> {
boolean postIds = PostService.isPostAd(ownerid, postId);
if (VotesPreferences.isEnabled()) {
boolean postIds = VotesService.isPostAd(ownerid, postId);
if (postIds) {
PostsPreferences.saveAdPostInfo(ownerid, postId);
sendToast("Этот пост помечен как рекламный");
if (postIds) {
VotesPreferences.saveAdPostInfo(ownerid, postId);
}
} else {
boolean postIds = PostService.isPostAd(ownerid, postId);
if (postIds) {
PostsPreferences.saveAdPostInfo(ownerid, postId);
if (!PostsPreferences.isEnabledMarking()) {
sendToast("Этот пост помечен как рекламный");
}
}
}
});
}
@@ -0,0 +1,43 @@
package ru.vtosters.hooks;
import android.content.Context;
import android.util.Log;
import com.vk.dto.newsfeed.entries.NewsEntry;
import com.vk.dto.newsfeed.entries.Post;
import com.vk.newsfeed.NewsEntryActionsAdapter;
import com.vk.newsfeed.holders.AdMarkHolder;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.sponsorpost.internal.Native;
import ru.vtosters.sponsorpost.utils.PostsPreferences;
public class PostsMenuHook {
private static final int id = 200;
public static void injectList(NewsEntryActionsAdapter actionsAdapter, NewsEntry newsEntry) {
if (newsEntry instanceof Post && Preferences.isValidSignature() && Native.canVote()) {
int ownerId = ((Post) newsEntry).b();
if (ownerId != AccountManagerUtils.getUserId() && PostsPreferences.isEnabled()) {
actionsAdapter.a(id, "SponsorPost");
}
}
}
public static void injectButtons(int i, NewsEntry newsEntry, Context context) {
if (newsEntry instanceof Post) {
Post post = (Post) newsEntry;
int ownerId = post.b();
int postId = post.P1();
int date = post.K();
AdMarkHolder.voteDialog(ownerId, postId, date, context);
} else {
Log.d("PostsMenuHook", "unsupported instance");
}
}
public static boolean isCustomButton(int i) {
return i == id;
}
}
@@ -6,6 +6,7 @@ import com.vk.core.network.Network;
import com.vk.core.util.DeviceIdProvider;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -13,6 +14,7 @@ import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.music.cache.MusicCacheImpl;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
@@ -260,9 +262,10 @@ public class CatalogJsonInjector {
+ sectionUrl
+ "&access_token="
+ AccountManagerUtils.getUserToken())
.a("Accept-Encoding", "gzip")
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
try {
var json = new JSONObject(Network.b(CLIENT_API).a(request).execute().a().g()).getJSONObject("response");
try (Response resp = Network.b(CLIENT_API).a(request).execute()) {
var json = new JSONObject(GzipDecompressor.decompressResponse(resp)).getJSONObject("response");
var catalogarr = json.optJSONObject("catalog").optJSONArray("sections").optJSONObject(0);
var title = catalogarr.optString("title");
@@ -276,4 +279,4 @@ public class CatalogJsonInjector {
Log.d("VTLMusic", "Error: " + e.getMessage());
}
}
}
}
@@ -311,6 +311,10 @@ public class Preferences {
return false;
}
public static String getId() {
return String.valueOf(AccountManagerUtils.getUserId());
}
public static void updateBuildNumber() {
try {
getPreferences().edit().putLong("setupTime", AndroidUtils.getGlobalContext().getPackageManager().getPackageInfo(AndroidUtils.getPackageName(), 0).lastUpdateTime).apply();
@@ -18,6 +18,7 @@ import ru.vtosters.lite.downloaders.messages.items.MiniUser;
import ru.vtosters.lite.proxy.ProxyUtils;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.File;
import java.io.FileOutputStream;
@@ -106,6 +107,7 @@ public class MessagesDownloader {
AccountManagerUtils.getUserToken());
var req = new Request.a()
.b(url)
.a("Accept-Encoding", "gzip")
.a();
Network.b(CLIENT_API).a(req).a(new Callback() {
@Override
@@ -116,7 +118,7 @@ public class MessagesDownloader {
@Override
public void a(Call call, Response response) {
try {
JSONObject obj = new JSONObject(response.a().g()).getJSONObject("response");
JSONObject obj = new JSONObject(GzipDecompressor.decompressResponse(response)).getJSONObject("response");
SparseArray<MiniUser> users = new SparseArray<>();
parseUsers(users, obj.optJSONArray("profiles"), false);
@@ -15,6 +15,7 @@ import ru.vtosters.lite.proxy.ProxyUtils;
import ru.vtosters.lite.proxy.api.VikaMobile;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.LifecycleUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
import java.time.LocalDate;
@@ -35,13 +36,14 @@ public class FoafBase {
public static JSONObject getBypassedOnlineInfo(int id) throws JSONException {
Request request = new Request.a()
.b(API_VKNEXT + id)
.a("Accept-Encoding", "gzip")
.a();
JSONObject dummy = new JSONObject();
dummy.put("last_seen", 0);
try (Response response = client.a(request).execute()) {
JSONObject online_info = new JSONObject(response.a().g()).getJSONObject("response").optJSONObject(Integer.toString(id));
JSONObject online_info = new JSONObject(GzipDecompressor.decompressResponse(response)).getJSONObject("response").optJSONObject(Integer.toString(id));
return online_info == null ? dummy : online_info;
} catch (Exception e) {
Log.e("GetBypassedOnlineInfo", e.getMessage());
@@ -52,12 +54,13 @@ public class FoafBase {
public static JSONObject getBypassedOnlineInfo(String ids) {
Request request = new Request.a()
.b(API_VKNEXT + ids)
.a("Accept-Encoding", "gzip")
.a();
JSONObject dummy = new JSONObject();
try (Response response = client.a(request).execute()) {
JSONObject online_info = new JSONObject(response.a().g()).getJSONObject("response").optJSONObject("response");
JSONObject online_info = new JSONObject(GzipDecompressor.decompressResponse(response)).getJSONObject("response").optJSONObject("response");
return online_info == null ? dummy : online_info;
} catch (Exception e) {
Log.e("GetBypassedOnlineInfo1", e.getMessage());
@@ -11,7 +11,9 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.music.downloader.M3UDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
import java.net.URLEncoder;
@@ -22,10 +24,10 @@ public class Genius {
private static final OkHttpClient client = VtOkHttpClient.getInstance();
public static String getTextMusic(MusicTrack musictrack) {
var uid = musictrack.y1();
var artist = removeExtras(musictrack.C);
var title = removeExtras(musictrack.f);
var duration = musictrack.h;
String uid = musictrack.y1();
String artist = removeExtras(M3UDownloader.getArtists(musictrack));
String title = removeExtras(musictrack.f);
int duration = musictrack.h;
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
Log.d("Genius", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
@@ -42,17 +44,18 @@ public class Genius {
}
Request request = new Request.a()
.b(URL + "/search/songs?q=" + URLEncoder.encode(artist + " " + track) + "&from_background=0" + "&page=1")
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
.b(String.format("%s/search/songs?q=%s&from_background=0&page=1", URL, URLEncoder.encode(artist + " " + track)))
.a("User-Agent", "Genius/5.21.3 (Android; Android 13; Google Pixel 4 XL)")
.a("Authorization", KEY)
.a("x-genius-app-background-request", "0")
.a("x-genius-logged-out", "true")
.a("host", "api.genius.com")
.a("Content-Type", "application/x-www-form-urlencoded")
.a("Accept-Encoding", "gzip")
.b()
.a();
try (Response resp = client.a(request).execute()) {
String payload = resp.a().g();
String payload = GzipDecompressor.decompressResponse(resp);
JSONArray sections = new JSONObject(payload).getJSONObject("response").getJSONArray("sections");
for (int i = 0; i < sections.length(); i++) {
@@ -86,17 +89,18 @@ public class Genius {
private static String getText(String track) {
Request request = new Request.a()
.b(URL + track + "?text_format=plain")
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
.b(String.format("%s%s?text_format=plain", URL, track))
.a("User-Agent", "Genius/5.21.3 (Android; Android 13; Google Pixel 4 XL)")
.a("Authorization", KEY)
.a("x-genius-app-background-request", "0")
.a("x-genius-logged-out", "true")
.a("host", "api.genius.com")
.a("Content-Type", "application/x-www-form-urlencoded")
.a("Accept-Encoding", "gzip")
.b()
.a();
try {
JSONObject payload = new JSONObject(client.a(request).execute().a().g());
try (Response resp = client.a(request).execute()) {
JSONObject payload = new JSONObject(GzipDecompressor.decompressResponse(resp));
if (!payload.has("response")) {
return AndroidUtils.getString("error_no_text");
@@ -107,4 +111,4 @@ public class Genius {
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getMessage();
}
}
}
}
@@ -14,6 +14,7 @@ import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.downloaders.AudioDownloader;
import ru.vtosters.lite.music.cache.MusicCacheImpl;
import ru.vtosters.lite.music.downloader.M3UDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
import java.io.IOException;
@@ -32,7 +33,7 @@ public class LastFMScrobbler {
public static void grabMusicTrack(MusicTrack musictrack) {
var uid = musictrack.y1();
var artist = musictrack.C;
var artist = M3UDownloader.getArtists(musictrack);
var title = musictrack.f;
var duration = musictrack.h;
var track_id = musictrack.d;
@@ -6,6 +6,7 @@ import bruhcollective.itaysonlab.libvkx.ILibVkxService;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
import bruhcollective.itaysonlab.libvkx.client.LibVKXClientImpl;
import com.vk.dto.music.MusicTrack;
import ru.vtosters.lite.music.downloader.M3UDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
@@ -19,7 +20,7 @@ public class MusicCacheImpl {
track.I != null ? track.I.getId() + "" : "-1",
track.f,
!TextUtils.isEmpty(track.g) ? track.g : "",
track.C,
M3UDownloader.getArtists(track),
track.I != null ? track.I.getTitle() : "",
track.K,
track.h,
@@ -13,6 +13,7 @@ import com.vk.dto.music.AlbumLink;
import com.vk.dto.music.MusicTrack;
import com.vk.dto.music.Thumb;
import org.json.JSONObject;
import ru.vtosters.lite.music.downloader.M3UDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
@@ -116,7 +117,7 @@ public class MusicCacheDb extends SQLiteOpenHelper implements AutoCloseable { //
vals.put(Constants.COLUMN_ALBUM_ID, track.I != null ? track.I.getId() + "" : "-1");
vals.put(Constants.COLUMN_TITLE, track.f);
vals.put(Constants.COLUMN_SUBTITLE, track.g);
vals.put(Constants.COLUMN_ARTIST, track.C);
vals.put(Constants.COLUMN_ARTIST, M3UDownloader.getArtists(track));
vals.put(Constants.COLUMN_ALBUM_TITLE, track.I != null ? track.I.getTitle() : "");
vals.put(Constants.COLUMN_EXPLICIT, Boolean.compare(track.K, true));
vals.put(Constants.COLUMN_DURATION, track.h);
@@ -7,6 +7,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.music.cache.MusicCacheImpl;
import ru.vtosters.lite.music.downloader.M3UDownloader;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.music.MusicCacheStorageUtils;
@@ -33,7 +34,7 @@ public class PlaylistHelper {
return createAlbum(
thumb != null ? thumb.h(600) : "",
albumLink.getTitle(),
track.C,
M3UDownloader.getArtists(track),
track.y1(),
albumLink.getId()
);
@@ -75,7 +76,7 @@ public class PlaylistHelper {
list.add(createAlbum(
thumb != null ? thumb.h(600) : "",
albumLink.getTitle(),
track.C,
M3UDownloader.getArtists(track),
track.y1(),
albumLink.getId()
));
@@ -7,10 +7,12 @@ import com.vk.dto.music.Playlist;
import java8.util.concurrent.CompletableFuture;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
import java.util.ArrayList;
@@ -50,17 +52,17 @@ public class PlaylistConverter {
var request = new Request.a()
.b(requestUrl)
.a("Accept-Encoding", "gzip")
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
try {
var response = CompletableFuture.supplyAsync(() -> {
try {
return Network.b(CLIENT_API).a(request).execute().a().g();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
).get();
try (Response resp = Network.b(CLIENT_API).a(request).execute()) {
return GzipDecompressor.decompressResponse(resp);
} catch (IOException e) {
throw new RuntimeException(e);
}
}).get();
var jsonObj = new JSONObject(response);
if (!jsonObj.has("response"))
return null;
@@ -7,9 +7,11 @@ import com.vk.dto.music.MusicTrack;
import java8.util.concurrent.CompletableFuture;
import okhttp3.Headers;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
import java.util.ArrayList;
@@ -44,12 +46,13 @@ public class AudioGet {
var request = new Request.a()
.b(requestUrl)
.a("Accept-Encoding", "gzip")
.a(Headers.a("User-Agent", Network.l.c().a(), "Content-Type", "application/x-www-form-urlencoded; charset=utf-8")).a();
try {
var response = CompletableFuture.supplyAsync(() -> {
try {
return Network.b(CLIENT_API).a(request).execute().a().g();
try (Response resp = Network.b(CLIENT_API).a(request).execute()) {
return GzipDecompressor.decompressResponse(resp);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -6,6 +6,7 @@ import android.util.Log;
import com.google.android.exoplayer2.source.hls.playlist.e;
import com.google.android.exoplayer2.source.hls.playlist.f;
import com.google.android.exoplayer2.source.hls.playlist.f.a;
import com.vk.dto.music.Artist;
import com.vk.dto.music.MusicTrack;
import java8.util.concurrent.CompletableFuture;
import java8.util.concurrent.CompletionException;
@@ -26,6 +27,7 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class M3UDownloader
implements ITrackDownloader {
@@ -151,7 +153,7 @@ public class M3UDownloader
}
static File getResultMp3File(File outDir, boolean cache, MusicTrack track) {
return new File(outDir, IOUtils.getValidFileName((cache ? "track" : track.C + " - " + getTitle(track)) + ".mp3"));
return new File(outDir, IOUtils.getValidFileName((cache ? "track" : getArtists(track) + " - " + getTitle(track)) + ".mp3"));
}
@Override
@@ -178,4 +180,14 @@ public class M3UDownloader
private static class Holder {
private static final M3UDownloader INSTANCE = new M3UDownloader();
}
}
public static String getArtists(MusicTrack track) {
return (track.L == null || track.I == null
? normalizeMetadata(track.C)
: normalizeMetadata(track.L.stream().map(Artist::w1).collect(Collectors.joining(", "))));
}
private static String normalizeMetadata(String in) {
return in.replaceAll("[\\\\/:*?\"<>|]", "");
}
}
@@ -105,6 +105,7 @@ public class OtherFragment extends TrackedMaterialPreferenceToolbarFragment {
findPreference("updateverifdata").setOnPreferenceClickListener(preference -> {
UsersList.getUsersList();
VTVerifications.isLoaded = false;
VTVerifications.load(requireContext());
AndroidUtils.sendToast(AndroidUtils.getString("data_updated"));
return true;
@@ -6,8 +6,10 @@ import android.os.Bundle;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.hooks.other.ThemesUtils;
import ru.vtosters.lite.ui.PreferenceFragmentUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.NetworkUtils;
import ru.vtosters.sponsorpost.data.Filter;
import ru.vtosters.sponsorpost.internal.VotesPreferences;
import ru.vtosters.sponsorpost.services.FilterService;
import ru.vtosters.sponsorpost.utils.FiltersPreferences;
import ru.vtosters.sponsorpost.utils.PostsPreferences;
@@ -35,6 +37,40 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
null
);
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Статистика блокировок");
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"SponsorPost",
"Заблокировано постов: " + PostsPreferences.getNumBlockedPosts(),
null,
null
);
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"SponsorPost фильтры",
"Заблокировано постов: " + FiltersPreferences.getNumBlockedPosts(),
null,
null
);
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"Сброс статистики",
null,
null,
preference -> {
FiltersPreferences.dropNumBlockedPosts();
PostsPreferences.dropNumBlockedPosts();
AndroidUtils.sendToast("Статистика сброшена");
return false;
}
);
PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Sponsor Post");
if (Preferences.serverFeaturesDisable()) {
@@ -49,9 +85,9 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
} else {
PreferenceFragmentUtils.addMaterialSwitchPreference(
getPreferenceScreen(),
"sponsorpost",
"",
"Фильтр постов",
"Получать списки рекламных постов в группах и ленте, которые не блокируются рекламными фильтрами",
"Получать списки рекламных постов в группах и ленте, которые не блокируются рекламными фильтрами\n\nРекомендуется использовать совместно со Стандартным фильтром",
null,
PostsPreferences.isEnabled(),
(preference, o) -> {
@@ -59,6 +95,61 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
return true;
}
);
PreferenceFragmentUtils.addMaterialSwitchPreference(
getPreferenceScreen(),
"",
"Не скрывать посты",
"Помечать посты рекламной пометкой, но не скрывать их полностью",
null,
PostsPreferences.isEnabledMarking(),
(preference, o) -> {
PostsPreferences.setEnabledMarking((boolean) o);
return true;
}
).setEnabled(PostsPreferences.isEnabled());
PreferenceFragmentUtils.addMaterialSwitchPreference(
getPreferenceScreen(),
"",
"Предварительные списки",
"Получать дополнительно более свежие списки которые ещё не попали в основной список. Нужно для активного голосования для блокировки постов. Возможно много ошибок!",
null,
VotesPreferences.isEnabled(),
(preference, o) -> {
VotesPreferences.setEnabled((boolean) o);
return true;
}
).setEnabled(PostsPreferences.isEnabled());
if (NetworkUtils.isNetworkConnected()) {
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"Обновить списки постов",
null,
null,
preference -> {
this.requireActivity().runOnUiThread(() -> {
Updates.updatePosts();
AndroidUtils.sendToast("Обновлено");
});
return false;
}
);
}
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"Телеграм чат",
"Помогите улучшить качество блокировки постов в нашем телеграм чате\n\nДля перехода в чат вам необходима последняя версия Telegram",
null,
preference -> {
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://t.me/vtosterschat/3559729")));
return false;
}
);
}
requireActivity().runOnUiThread(() -> {
@@ -123,6 +214,31 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
);
}
PreferenceFragmentUtils.addMaterialSwitchPreference(
getPreferenceScreen(),
"",
"Не блокировать посты",
"Помечать посты заблокированные фильтрами",
null,
FiltersPreferences.isEnabledMarking(),
(preference, o) -> {
FiltersPreferences.setEnabledMarking((boolean) o);
return true;
}
);
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"Телеграм чат",
"Помогите улучшить качество фильтров обсудив работу в нашем телеграм чате\n\nДля перехода в чат вам необходима последняя версия Telegram",
null,
preference -> {
requireContext().startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("https://t.me/vtosterschat/3559732")));
return false;
}
);
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
@@ -139,6 +255,20 @@ public class SponsorPostFragment extends TrackedMaterialPreferenceToolbarFragmen
}
}
);
if (Preferences.dev()) {
PreferenceFragmentUtils.addPreference(
getPreferenceScreen(),
"",
"Сбросить токен пользователя",
null,
null,
preference -> {
VotesPreferences.remUserToken();
return false;
}
);
}
}
@Override
@@ -5,6 +5,7 @@ import okhttp3.*;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
@@ -25,6 +26,7 @@ public class OTAUtils {
public void loadData(boolean isManualCheck) {
Request release = new Request.a()
.b(LATEST_RELEASE_URL)
.a("Accept-Encoding", "gzip")
.a();
mClient.a(release).a(new Callback() {
@@ -46,12 +48,13 @@ public class OTAUtils {
});
}
void setData(Response response, boolean isManualCheck) throws IOException, JSONException {
mReleaseJson = new JSONObject(response.a().g());
void setData(Response response, boolean isManualCheck) throws JSONException, IOException {
mReleaseJson = new JSONObject(GzipDecompressor.decompressResponse(response));
String tag = mReleaseJson.getString("tag_name");
Request commit = new Request.a()
.b(String.format(LATEST_RELEASE_COMMIT_URL, tag))
.a("Accept-Encoding", "gzip")
.a();
mClient.a(commit).a(new Callback() {
@@ -62,15 +65,15 @@ public class OTAUtils {
}
@Override
public void a(Call call, Response response) throws IOException {
public void a(Call call, Response response) {
try {
mCommitJson = new JSONObject(response.a().g());
mCommitJson = new JSONObject(GzipDecompressor.decompressResponse(response));
mCommitSHA = mCommitJson.getJSONObject("object").getString("sha");
if (isNewVersion())
mListener.onUpdateApplied(isManualCheck);
else
mListener.onUpdateLatest(isManualCheck);
} catch (NullPointerException | JSONException e) {
} catch (NullPointerException | JSONException | IOException e) {
e.printStackTrace();
mListener.onUpdateError();
}
@@ -3,6 +3,7 @@ package ru.vtosters.lite.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.vk.core.network.Network;
import com.vk.navigation.NavigatorKeys;
import okhttp3.*;
import org.json.JSONArray;
@@ -10,12 +11,11 @@ import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;
import static ru.vtosters.hooks.other.Preferences.getBoolValue;
@@ -44,13 +44,14 @@ public class VTVerifications {
Request request = new Request.a()
.b("https://vtosters.app/vktoaster/getGalo4kiBatch")
.a(RequestBody.a(MediaType.b("application/json; charset=UTF-8"), "{\"types\":[0,228,404]}"))
.a("Accept-Encoding", "gzip")
.a();
sClient.a(request).a(new Callback() {
@Override
public void a(Call call, Response response) {
try {
String payload = response.a().g();
String payload = GzipDecompressor.decompressResponse(response);
parseJson(payload);
prefs.edit()
.putString("ids", payload)
@@ -6,6 +6,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.sponsorpost.internal.VotesPreferences;
import ru.vtosters.sponsorpost.utils.FiltersPreferences;
import ru.vtosters.sponsorpost.utils.PostsPreferences;
@@ -185,7 +186,7 @@ public class NewsFeedFiltersUtils {
return json;
}
private static boolean needToSave(JSONObject post, String source, boolean needToShowToast) throws JSONException {
private static boolean needToSave(JSONObject post, String source, boolean needToNotifyBlock) throws JSONException {
String type = post.optString("type");
if (isAds(post, type)) {
@@ -198,58 +199,84 @@ public class NewsFeedFiltersUtils {
|| type.endsWith("playlists")
|| type.endsWith("groups")))) {
logRemovedPost(post, source, "authors", needToShowToast);
logRemovedPost(post, source, "authors", needToNotifyBlock);
return false;
}
if (postsrecomm() && (type.equals("inline_user_rec") || type.equals("live_recommended"))) {
logRemovedPost(post, source, "postsrecomm", needToShowToast);
logRemovedPost(post, source, "postsrecomm", needToNotifyBlock);
return false;
}
if (friendsrecomm() && (type.equals("user_rec") || type.equals("friends_recomm"))) {
logRemovedPost(post, source, "friendsrecomm", needToShowToast);
logRemovedPost(post, source, "friendsrecomm", needToNotifyBlock);
return false;
}
if (adsgroup() && post.optInt("marked_as_ads") == 1 && !isWhitelistedAd(post)) {
logRemovedPost(post, source, "marked_as_ads", needToShowToast);
return false;
if (adsgroup() && post.optInt("marked_as_ads") == 1 && !post.optBoolean("sponsorpost") && !isWhitelistedAd(post)) {
logRemovedPost(post, source, "marked_as_ads", needToNotifyBlock);
return needToNotifyBlock;
}
if (PostsPreferences.isPostAd(getOwnerId(post), getPostId(post)) && !isWhitelistedAd(post)) {
logRemovedPost(post, source, "sponsorpost", needToShowToast);
return false;
if (PostsPreferences.isPostAd(getOwnerId(post), getPostId(post)) && !post.optBoolean("sponsorpost") && !isWhitelistedAd(post)) {
logRemovedPost(post, source, "sponsorpost", needToNotifyBlock);
PostsPreferences.incrementNumBlockedPosts();
if (PostsPreferences.isEnabledMarking() || needToNotifyBlock) {
addSponsorPostMark(post);
return true;
} else {
return false;
}
}
if (sponsorFilters(post.optString("text")) && !isWhitelistedFilters(post)) {
logRemovedPost(post, source, "sponsorpost filter", needToShowToast);
return false;
if (VotesPreferences.isPostAd(getOwnerId(post), getPostId(post)) && !post.optBoolean("sponsorpost") && !isWhitelistedAd(post)) {
logRemovedPost(post, source, "sponsorpost vote base", needToNotifyBlock);
addSponsorPostMark(post);
return true;
}
if (sponsorFilters(post.optString("text")) && !post.optBoolean("sponsorpost") && !isWhitelistedFilters(post)) {
logRemovedPost(post, source, "sponsorpost filter", needToNotifyBlock);
FiltersPreferences.incrementNumBlockedPosts();
if (FiltersPreferences.isEnabledMarking() || needToNotifyBlock) {
addSponsorPostMark(post);
return true;
} else {
return false;
}
}
if (checkCopyright(post)) {
logRemovedPost(post, source, "copyright filters", needToShowToast);
return false;
logRemovedPost(post, source, "copyright filters", needToNotifyBlock);
FiltersPreferences.incrementNumBlockedPosts();
return needToNotifyBlock;
}
if (checkCaption(post)) {
logRemovedPost(post, source, "caption filters", needToShowToast);
return false;
logRemovedPost(post, source, "caption filters", needToNotifyBlock);
return needToNotifyBlock;
}
if (hasMiniAppAds(post) && !isWhitelistedFilters(post)) {
logRemovedPost(post, source, "miniapps ban", needToShowToast);
return false;
logRemovedPost(post, source, "miniapps ban", needToNotifyBlock);
return needToNotifyBlock;
}
if (NewsFeedFiltersUtils.injectFiltersReposts(post) && !isWhitelistedFilters(post)) {
logRemovedPost(post, source, "repost ad", needToShowToast);
return false;
logRemovedPost(post, source, "repost ad", needToNotifyBlock);
return needToNotifyBlock;
}
return true;
}
private static void addSponsorPostMark(JSONObject post) throws JSONException {
post.putOpt("marked_as_ads", 1);
post.putOpt("sponsorpost", true);
}
public static JSONArray feedInject(JSONArray items, boolean needToShowToast) {
if (items.length() == 0) return items;
@@ -276,24 +303,26 @@ public class NewsFeedFiltersUtils {
public static boolean sponsorFilters(String text) {
String textInLowerCase = text.toLowerCase();
Set<String> list = filters.stream()
.filter(adword -> !adword.isEmpty())
.collect(Collectors.toSet());
if (!list.isEmpty()) {
return list.stream().anyMatch(adword -> {
if (textInLowerCase.contains(adword.toLowerCase())) {
return filters.stream()
.map(String::toLowerCase)
.filter(adword -> !adword.isEmpty() && textInLowerCase.contains(adword))
.peek(adword -> {
if (dev()) {
Log.d("NewsfeedAdBlockV2", text);
Log.d("NewsfeedAdBlockV2", "Block word: " + adword);
}
return true;
}
return false;
});
}
})
.findAny()
.isPresent();
}
return false;
public static String sponsorFiltersBanWord(String text) {
String textInLowerCase = text.toLowerCase();
return filters.stream()
.map(String::toLowerCase)
.filter(adword -> !adword.isEmpty() && textInLowerCase.contains(adword))
.findAny()
.orElse(null);
}
@@ -0,0 +1,20 @@
package ru.vtosters.sponsorpost.internal;
import androidx.annotation.Nullable;
public class Native {
public static boolean canVote;
public static boolean canVote() {
return canVote;
}
@Nullable
public static native String sig();
@Nullable
public static native String time();
@Nullable
public static native String pkey();
}
@@ -0,0 +1,103 @@
package ru.vtosters.sponsorpost.internal;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import ru.vtosters.lite.utils.AndroidUtils;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class VotesPreferences {
private static final SharedPreferences preferences;
static {
preferences = getPreferences();
}
private static SharedPreferences getPreferences() {
return AndroidUtils.getGlobalContext().getSharedPreferences("ru.vtosters.sponsorpost.votes.prefs", Context.MODE_PRIVATE);
}
public static boolean isEnabled() {
return preferences.getBoolean("sponsortesting", false);
}
public static void setEnabled(boolean status) {
preferences.edit().putBoolean("sponsortesting", status).apply();
}
public static void setUserToken(String token) {
preferences.edit()
.putString("token", token)
.apply();
}
public static void remUserToken() {
preferences.edit()
.remove("token")
.apply();
}
public static String getUserToken() {
return preferences.getString("token", "");
}
public static void savePosts(List<String> posts) {
preferences.edit()
.putStringSet("posts", new HashSet<>(posts))
.apply();
}
public static void saveGroupsIds(List<String> ids) {
preferences.edit()
.putStringSet("groupIds", new HashSet<>(ids))
.apply();
}
public static void saveGroupSpecifiedPosts(List<String> postsIds, Long ownerId) {
Set<String> stringSet = postsIds.stream()
.map(post -> ownerId + "_" + post)
.collect(Collectors.toSet());
preferences.edit()
.putStringSet(ownerId + "_posts", stringSet)
.apply();
}
public static void saveAdPostInfo(long ownerId, long postId) {
Set<String> currentStringSet = preferences.getStringSet("posts", new HashSet<>());
Set<String> newStringSet = new HashSet<>(currentStringSet);
newStringSet.add(ownerId + "_" + postId);
Log.d("SponsorPost", ownerId + "_" + postId);
preferences.edit()
.putStringSet("posts", newStringSet)
.apply();
}
public static boolean isGroupAd(long ownerId) {
Set<String> isGroupAd = preferences.getStringSet("groupIds", new HashSet<>());
if (!isGroupAd.isEmpty() && isEnabled()) {
return isGroupAd.contains(Long.toString(ownerId));
} else {
return false;
}
}
public static boolean isPostAd(long ownerId, long postId) {
if (isEnabled() && isGroupAd(ownerId)) {
Set<String> hasSpecifiedGroupPosts = preferences.getStringSet(ownerId + "_posts", new HashSet<>());
Set<String> hasPost = preferences.getStringSet("posts", new HashSet<>());
return hasPost.contains(ownerId + "_" + postId) || hasSpecifiedGroupPosts.contains(ownerId + "_" + postId);
} else {
return false;
}
}
}
@@ -0,0 +1,153 @@
package ru.vtosters.sponsorpost.internal;
import android.net.Uri;
import android.util.Log;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.sponsorpost.utils.ApiUtils;
import ru.vtosters.sponsorpost.utils.GzipDecompressor;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class VotesService {
private static final OkHttpClient client = new OkHttpClient();
private static final String apiPath = ApiUtils.getURL() + "/votes";
private static final String userPath = ApiUtils.getURL() + "/users";
public static Map<String, List<String>> getPosts(Long date) {
String getFromDate = date > 0 ? ("&date=" + date) : "";
Request request = new Request.a()
.b(apiPath + "/getAllPostIds" + "?needProd=true" + getFromDate)
.a("Content-Type", "application/json")
.a("Accept-Encoding", "gzip")
.a();
try (Response response = client.a(request).execute()) {
if (response.h()) {
return parseJSON(new JSONObject(GzipDecompressor.decompressResponse(response)));
} else {
throw new RuntimeException("Failed to get posts: " + response.l());
}
} catch (IOException | JSONException e) {
throw new RuntimeException(e);
}
}
private static Map<String, List<String>> parseJSON(JSONObject object) throws JSONException {
String PROD_KEY = "prod";
String VOTE_KEY = "vote";
JSONArray prodBase = object.getJSONArray(PROD_KEY);
JSONArray testBase = object.getJSONArray(VOTE_KEY);
if (prodBase.length() == 0 && testBase.length() == 0) {
return Collections.emptyMap();
}
List<String> prodList = IntStream.range(0, prodBase.length())
.mapToObj(prodBase::optString)
.filter(Objects::nonNull)
.collect(Collectors.toList());
List<String> voteList = IntStream.range(0, testBase.length())
.mapToObj(testBase::optString)
.filter(Objects::nonNull)
.collect(Collectors.toList());
return Map.of(PROD_KEY, prodList, VOTE_KEY, voteList);
}
public static Map<String, List<String>> getPostIdsByOwnerId(Long ownerId, Long date) {
String getFromDate = date > 0 ? ("&date=" + date) : "";
String requestUrl = apiPath + "/getPostIdsByOwnerId" + "?ownerId=" + ownerId + getFromDate + "&needProd=true";
Request request = new Request.a()
.b(requestUrl)
.a("Content-Type", "application/json")
.a("Accept-Encoding", "gzip")
.a();
try (Response response = client.a(request).execute()) {
if (response.h()) {
return parseJSON(new JSONObject(GzipDecompressor.decompressResponse(response)));
} else {
throw new RuntimeException("Failed to get postIdsByOwnerId: " + response.l());
}
} catch (IOException | JSONException e) {
throw new RuntimeException(e);
}
}
public static Map<String, List<String>> getOwnerIds() {
String requestUrl = apiPath + "/getOwnerIds" + "?needProd=true";
Request request = new Request.a()
.b(requestUrl)
.a("Content-Type", "application/json")
.a("Accept-Encoding", "gzip")
.a();
try (Response response = client.a(request).execute()) {
if (response.h()) {
return parseJSON(new JSONObject(GzipDecompressor.decompressResponse(response)));
} else {
throw new RuntimeException("Failed to get ownersIds: " + response.l());
}
} catch (IOException | JSONException e) {
throw new RuntimeException(e);
}
}
public static JSONObject ratePost(int ownerId, int postId, int date, boolean isAd) {
String token = VotesPreferences.getUserToken() == null || VotesPreferences.getUserToken().isEmpty() ? getVoteToken() : VotesPreferences.getUserToken();
String requestUrl = apiPath + (isAd ? "/dislike" : "/like") + "?ownerId=" + ownerId + "&postId=" + postId+ "&postDate=" + date + "&token=" + Uri.encode(token);
Request request = new Request.a()
.b(requestUrl)
.a("Content-Type", "application/json")
.a();
try (Response response = client.a(request).execute()) {
return new JSONObject(GzipDecompressor.decompressResponse(response));
} catch (IOException | JSONException e) {
throw new RuntimeException(e);
}
}
public static String getVoteToken() {
String requestUrl = userPath + "/getUserToken" + "?private_key=" + Uri.encode(Native.pkey());
Request request = new Request.a()
.b(requestUrl)
.a("Content-Type", "application/json")
.a("Timestamp", Native.time())
.a("Signature", Native.sig())
.a();
try (Response response = client.a(request).execute()) {
String userToken = new JSONObject(GzipDecompressor.decompressResponse(response)).getString("token");
VotesPreferences.setUserToken(userToken);
return userToken;
} catch (IOException | JSONException e) {
throw new RuntimeException(e);
}
}
public static boolean isPostAd(long ownerId, long postId) {
String requestUrl = apiPath + "/isPostAdvert?post=" + ownerId + "_" + postId + "&needProd=true";
Request request = new Request.a()
.b(requestUrl)
.a("Content-Type", "application/json")
.a();
try (Response response = client.a(request).execute()) {
if (response.h()) {
return Boolean.parseBoolean(GzipDecompressor.decompressResponse(response));
} else {
throw new RuntimeException("Failed to check post for ad status: " + response.l());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -42,20 +42,7 @@ public class FilterService {
try (Response response = client.a(request).execute()) {
// Check if the response is successful
if (response.h()) {
// Determine the response encoding
String encoding = response.a("Content-Encoding");
String resp;
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body
resp = GzipDecompressor.decompress(response.a().b());
} else {
// Retrieve the response body directly
resp = response.a().g();
}
// Parse the response body as a JSONArray and extract filter objects
return parseJSON(new JSONArray(resp));
return parseJSON(new JSONArray(GzipDecompressor.decompressResponse(response)));
} else {
if (!FiltersPreferences.getAllFilterIds().isEmpty()) {
return FiltersPreferences.getAllDownloadedFilters(); // check for offline server to get local filters
@@ -75,11 +62,12 @@ public class FilterService {
public static Set<String> downloadFilter(String link) {
Request request = new Request.a()
.b(link)
.a("Accept-Encoding", "gzip")
.a();
try (Response response = client.a(request).execute()) {
if (response.h()) {
return stringToSet(response.a().g());
return stringToSet(GzipDecompressor.decompressResponse(response));
} else {
throw new RuntimeException("Failed to download filter: " + response.l());
}
@@ -39,17 +39,7 @@ public class PostService {
try (Response response = client.a(request).execute()) {
// Check if the response is successful
if (response.h()) {
// Determine the response encoding
String encoding = response.a("Content-Encoding");
// Handle GZIP-compressed responses
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body and parse JSON data
return parseJSONPosts(new JSONArray(GzipDecompressor.decompress(response.a().b())));
} else {
// Parse JSON data from the response body
return parseJSONPosts(new JSONArray(response.a().g()));
}
return parseJSONPosts(new JSONArray(GzipDecompressor.decompressResponse(response)));
} else {
// Handle error response
throw new RuntimeException("Failed to get posts: " + response.l());
@@ -78,20 +68,7 @@ public class PostService {
try (Response response = client.a(request).execute()) {
// Check if the response is successful
if (response.h()) {
// Determine the response encoding
String encoding = response.a("Content-Encoding");
String resp;
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body
resp = GzipDecompressor.decompress(response.a().b());
} else {
// Retrieve the response body directly
resp = response.a().g();
}
// Extract the boolean value indicating whether the post is an ad
return Boolean.parseBoolean(resp);
return Boolean.parseBoolean(GzipDecompressor.decompressResponse(response));
} else {
// Handle error response
throw new RuntimeException("Failed to check post for ad status: " + response.l());
@@ -101,10 +78,19 @@ public class PostService {
}
}
public static List<String> getAllPostsIds() {
public static List<String> getAllPostsIds(Long date) {
String getFromDate;
// Get posts older than the specified date (if positive) or all posts (if zero or negative or empty)
if (date > 0) {
getFromDate = ("?date=" + date);
} else {
// No date parameter for retrieving all posts
getFromDate = "";
}
// Create a GET request for retrieving all post IDs
Request request = new Request.a()
.b(apiPath + "/getAllPostIds")
.b(apiPath + "/getAllPostIds" + getFromDate)
.a("Content-Type", "application/json")
.a("Accept-Encoding", "gzip")
.a();
@@ -112,17 +98,7 @@ public class PostService {
try (Response response = client.a(request).execute()) {
// Check if the response is successful
if (response.h()) {
// Determine the response encoding
String encoding = response.a("Content-Encoding");
// Handle GZIP-compressed responses
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body and extract the first element as a list of post IDs
return new ArrayList<>(Collections.singleton(GzipDecompressor.decompress(response.a().b())));
} else {
// Extract the first element as a list of post IDs
return new ArrayList<>(Collections.singleton(response.a().g()));
}
return new ArrayList<>(Collections.singleton(GzipDecompressor.decompressResponse(response)));
} else {
// Handle error response
throw new RuntimeException("Failed to get posts IDs: " + response.l());
@@ -137,7 +113,7 @@ public class PostService {
// Retrieve post IDs for a specific owner and date
// If date is positive, get posts older than the specified date
// Otherwise, get all posts for the owner
String getFromDate = date > 0 ? ("?date=" + date) : "";
String getFromDate = date > 0 ? ("&date=" + date) : "";
// Construct the API request URL
String requestUrl = apiPath + "/getPostIdsByOwnerId" + "?ownerId=" + ownerId + getFromDate;
@@ -152,20 +128,7 @@ public class PostService {
try (Response response = client.a(request).execute()) {
// Check if the response is successful
if (response.h()) {
// Determine the response encoding
String encoding = response.a("Content-Encoding");
String resp;
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body
resp = GzipDecompressor.decompress(response.a().b());
} else {
// Retrieve the response body directly
resp = response.a().g();
}
// Parse the response body as a JSONArray and extract post IDs
return parseJSONIds(new JSONArray(resp));
return parseJSONIds(new JSONArray(GzipDecompressor.decompressResponse(response)));
} else {
// Handle error response
throw new RuntimeException("Failed to get postIdsByOwnerId: " + response.l());
@@ -192,20 +155,7 @@ public class PostService {
try (Response response = client.a(request).execute()) {
// Check if the response is successful
if (response.h()) {
// Determine the response encoding
String encoding = response.a("Content-Encoding");
String resp;
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body
resp = GzipDecompressor.decompress(response.a().b());
} else {
// Retrieve the response body directly
resp = response.a().g();
}
// Parse the response body as a JSONArray and extract owner IDs
return parseJSONIds(new JSONArray(resp));
return parseJSONIds(new JSONArray(GzipDecompressor.decompressResponse(response)));
} else {
// Handle error response
throw new RuntimeException("Failed to get ownersIds: " + response.l());
@@ -31,6 +31,26 @@ public class FiltersPreferences {
return AndroidUtils.getGlobalContext().getSharedPreferences("ru.vtosters.sponsorpost.filters.prefs", Context.MODE_PRIVATE);
}
public static boolean isEnabledMarking() {
return preferences.getBoolean("sponsorpost_filters_marking", false);
}
public static void setEnabledMarking(boolean status) {
preferences.edit().putBoolean("sponsorpost_filters_marking", status).apply();
}
public static int getNumBlockedPosts() {
return preferences.getInt("numBlockedPosts", 0);
}
public static void incrementNumBlockedPosts() {
preferences.edit().putInt("numBlockedPosts", getNumBlockedPosts() + 1).apply();
}
public static void dropNumBlockedPosts() {
preferences.edit().putInt("numBlockedPosts", 0).apply();
}
public static void clearAllCachedLists() {
SharedPreferences.Editor editor = preferences.edit();
@@ -1,5 +1,8 @@
package ru.vtosters.sponsorpost.utils;
import android.util.Log;
import okhttp3.Response;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -26,4 +29,17 @@ public class GzipDecompressor {
throw new RuntimeException(e);
}
}
public static String decompressResponse(Response response) throws IOException {
String encoding = response.a("Content-Encoding");
if (encoding != null && encoding.equals("gzip")) {
// Decompress the response body
Log.d("GZIP", "true, link " + response.o().g());
return GzipDecompressor.decompress(response.a().b());
} else {
// Retrieve the response body directly
Log.d("GZIP", "false, link " + response.o().g());
return response.a().g();
}
}
}
@@ -30,6 +30,14 @@ public class PostsPreferences {
preferences.edit().putBoolean("sponsorpost", status).apply();
}
public static boolean isEnabledMarking() {
return preferences.getBoolean("sponsorpost_marking", false);
}
public static void setEnabledMarking(boolean status) {
preferences.edit().putBoolean("sponsorpost_marking", status).apply();
}
public static void savePosts(List<Post> posts) {
Set<String> stringSet = posts.stream()
.map(post -> post.getOwnerId() + "_" + post.getPostId())
@@ -40,7 +48,13 @@ public class PostsPreferences {
.apply();
}
public static void saveGroupSpecifiedPosts(List<Long> postsIds, Long ownerId) {
public static void savePostsStr(List<String> posts) {
preferences.edit()
.putStringSet("posts", new HashSet<>(posts))
.apply();
}
public static void saveGroupSpecifiedPosts(List<?> postsIds, Long ownerId) {
Set<String> stringSet = postsIds.stream()
.map(post -> ownerId + "_" + post)
.collect(Collectors.toSet());
@@ -50,7 +64,7 @@ public class PostsPreferences {
.apply();
}
public static void saveGroupsIds(List<Long> ids) {
public static void saveGroupsIds(List<?> ids) {
Set<String> stringSet = ids.stream().map(String::valueOf).collect(Collectors.toSet());
preferences.edit()
@@ -81,6 +95,18 @@ public class PostsPreferences {
}
}
public static int getNumBlockedPosts() {
return preferences.getInt("numBlockedPosts", 0);
}
public static void incrementNumBlockedPosts() {
preferences.edit().putInt("numBlockedPosts", getNumBlockedPosts() + 1).apply();
}
public static void dropNumBlockedPosts() {
preferences.edit().putInt("numBlockedPosts", 0).apply();
}
public static boolean isPostAd(long ownerId, long postId) {
if (isEnabled() && isGroupAd(ownerId)) {
Set<String> hasSpecifiedGroupPosts = preferences.getStringSet(ownerId + "_posts", new HashSet<>());
@@ -1,14 +1,16 @@
package ru.vtosters.sponsorpost.utils;
import ru.vtosters.hooks.other.Preferences;
import ru.vtosters.lite.utils.NetworkUtils;
import ru.vtosters.lite.utils.newsfeed.NewsFeedFiltersUtils;
import ru.vtosters.sponsorpost.data.Filter;
import ru.vtosters.sponsorpost.data.Post;
import ru.vtosters.sponsorpost.internal.VotesPreferences;
import ru.vtosters.sponsorpost.internal.VotesService;
import ru.vtosters.sponsorpost.services.FilterService;
import ru.vtosters.sponsorpost.services.PostService;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -59,16 +61,31 @@ public class Updates {
long weekAgo = currentTime - TimeUnit.DAYS.toMillis(7);
if (PostsPreferences.isEnabled() && NetworkUtils.isNetworkConnected()) {
List<Post> posts = PostService.getPosts(weekAgo);
List<Long> groupIds = PostService.getOwnerIds();
if (VotesPreferences.isEnabled()) {
Map<String, List<String>> posts = VotesService.getPosts(weekAgo / 1000);
Map<String, List<String>> groupIds = VotesService.getOwnerIds();
if (!posts.isEmpty()) {
PostsPreferences.savePosts(posts);
}
if (!posts.isEmpty()) {
PostsPreferences.savePostsStr(posts.get("prod"));
VotesPreferences.savePosts(posts.get("vote"));
}
if (!groupIds.isEmpty()) {
PostsPreferences.saveGroupsIds(groupIds);
if (!groupIds.isEmpty()) {
PostsPreferences.saveGroupsIds(groupIds.get("prod"));
VotesPreferences.saveGroupsIds(groupIds.get("vote"));
}
} else {
List<String> posts = PostService.getAllPostsIds(weekAgo / 1000);
List<Long> groupIds = PostService.getOwnerIds();
if (!posts.isEmpty()) {
PostsPreferences.savePostsStr(posts);
}
if (!groupIds.isEmpty()) {
PostsPreferences.saveGroupsIds(groupIds);
}
}
}
}
}
}
@@ -891,6 +891,17 @@
if-eqz v0, :cond_a
invoke-static {p1}, Lru/vtosters/hooks/PostsMenuHook;->isCustomButton(I)Z
move-result v2
if-eqz v2, :cond_99
invoke-static {p1, p2, v0}, Lru/vtosters/hooks/PostsMenuHook;->injectButtons(ILcom/vk/dto/newsfeed/entries/NewsEntry;Landroid/content/Context;)V
return-void
:cond_99
invoke-static {v0}, Lcom/vk/core/util/ContextExtKt;->e(Landroid/content/Context;)Landroid/app/Activity;
move-result-object v2
@@ -1536,6 +1536,10 @@
invoke-virtual {v0, v1, v2}, Lcom/vk/newsfeed/NewsEntryActionsAdapter;->a(ILjava/lang/CharSequence;)V
:cond_26
iget-object v1, p0, Lcom/vk/newsfeed/NewsEntryActionsMenuBuilder;->e:Lcom/vk/dto/newsfeed/entries/NewsEntry;
invoke-static {v0, v1}, Lru/vtosters/hooks/PostsMenuHook;->injectList(Lcom/vk/newsfeed/NewsEntryActionsAdapter;Lcom/vk/dto/newsfeed/entries/NewsEntry;)V
return-object p1
.end method
@@ -1367,6 +1367,10 @@
invoke-virtual {v1, v2, v3, v4}, Lcom/vk/newsfeed/NewsEntryActionsAdapter;->b(III)V
:cond_35
iget-object v2, v0, Lcom/vk/newsfeed/PostViewActionsMenuBuilder;->b:Lcom/vk/dto/newsfeed/entries/NewsEntry;
invoke-static {v1, v2}, Lru/vtosters/hooks/PostsMenuHook;->injectList(Lcom/vk/newsfeed/NewsEntryActionsAdapter;Lcom/vk/dto/newsfeed/entries/NewsEntry;)V
return-object v17
.end method
@@ -1,187 +0,0 @@
.class public final Lcom/vk/newsfeed/holders/AdMarkHolder;
.super Lcom/vk/newsfeed/holders/BaseNewsEntryHolder;
.source "AdMarkHolder.kt"
# annotations
.annotation system Ldalvik/annotation/Signature;
value = {
"Lcom/vk/newsfeed/holders/BaseNewsEntryHolder<",
"Lcom/vk/dto/newsfeed/entries/NewsEntry;",
">;"
}
.end annotation
# instance fields
.field private final F:Landroid/widget/TextView;
# direct methods
.method public constructor <init>(Landroid/view/ViewGroup;)V
.locals 3
const v0, 0x7f0d0307
.line 1
invoke-direct {p0, v0, p1}, Lcom/vk/newsfeed/holders/BaseNewsEntryHolder;-><init>(ILandroid/view/ViewGroup;)V
.line 2
iget-object p1, p0, Landroidx/recyclerview/widget/RecyclerView$ViewHolder;->itemView:Landroid/view/View;
const-string v0, "itemView"
invoke-static {p1, v0}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/String;)V
const/4 v0, 0x0
const v1, 0x7f0a0d4e
const/4 v2, 0x2
invoke-static {p1, v1, v0, v2, v0}, Lcom/vk/extensions/ViewExtKt;->a(Landroid/view/View;ILkotlin/jvm/b/Functions2;ILjava/lang/Object;)Landroid/view/View;
move-result-object p1
check-cast p1, Landroid/widget/TextView;
iput-object p1, p0, Lcom/vk/newsfeed/holders/AdMarkHolder;->F:Landroid/widget/TextView;
return-void
.end method
# virtual methods
.method public b(Lcom/vk/dto/newsfeed/entries/NewsEntry;)V
.locals 4
.line 2
instance-of v0, p1, Lcom/vk/dto/newsfeed/entries/Post;
const/4 v1, 0x0
const/4 v2, 0x0
if-eqz v0, :cond_0
check-cast p1, Lcom/vk/dto/newsfeed/entries/Post;
invoke-virtual {p1}, Lcom/vk/dto/newsfeed/entries/Post;->L1()Z
move-result p1
if-eqz p1, :cond_2
const p1, 0x7f0808cf
const v0, 0x7f040256
.line 3
invoke-static {p1, v0}, Lcom/vk/core/ui/themes/VKThemeHelper;->a(II)Lcom/vk/core/drawable/RecoloredDrawable;
move-result-object p1
const v0, 0x7f120def
.line 4
invoke-virtual {p0, v0}, Lcom/vtosters/lite/ui/holder/RecyclerHolder;->m(I)Ljava/lang/String;
move-result-object v0
.line 5
invoke-virtual {p0}, Lcom/vtosters/lite/ui/holder/RecyclerHolder;->e0()Landroid/content/res/Resources;
move-result-object v1
const v3, 0x7f0701b8
invoke-virtual {v1, v3}, Landroid/content/res/Resources;->getDimensionPixelSize(I)I
move-result v1
goto :goto_1
.line 6
:cond_0
instance-of v0, p1, Lcom/vk/dto/newsfeed/entries/PromoPost;
if-eqz v0, :cond_2
check-cast p1, Lcom/vk/dto/newsfeed/entries/PromoPost;
invoke-virtual {p1}, Lcom/vk/dto/newsfeed/entries/PromoPost;->E1()Ljava/lang/String;
move-result-object v0
invoke-interface {v0}, Ljava/lang/CharSequence;->length()I
move-result v0
if-lez v0, :cond_1
const/4 v0, 0x1
goto :goto_0
:cond_1
const/4 v0, 0x0
:goto_0
if-eqz v0, :cond_2
.line 7
invoke-virtual {p1}, Lcom/vk/dto/newsfeed/entries/PromoPost;->E1()Ljava/lang/String;
move-result-object p1
.line 8
invoke-virtual {p0}, Lcom/vtosters/lite/ui/holder/RecyclerHolder;->e0()Landroid/content/res/Resources;
move-result-object v0
const v1, 0x7f0701b9
invoke-virtual {v0, v1}, Landroid/content/res/Resources;->getDimensionPixelSize(I)I
move-result v1
move-object v0, p1
move-object p1, v2
goto :goto_1
:cond_2
move-object p1, v2
move-object v0, p1
.line 9
:goto_1
iget-object v3, p0, Lcom/vk/newsfeed/holders/AdMarkHolder;->F:Landroid/widget/TextView;
invoke-virtual {v3, p1, v2, v2, v2}, Landroid/widget/TextView;->setCompoundDrawablesRelativeWithIntrinsicBounds(Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;Landroid/graphics/drawable/Drawable;)V
.line 10
iget-object p1, p0, Lcom/vk/newsfeed/holders/AdMarkHolder;->F:Landroid/widget/TextView;
invoke-virtual {p1, v1}, Landroid/widget/TextView;->setMinHeight(I)V
.line 11
iget-object p1, p0, Lcom/vk/newsfeed/holders/AdMarkHolder;->F:Landroid/widget/TextView;
invoke-virtual {p1, v0}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
return-void
.end method
.method public bridge synthetic b(Ljava/lang/Object;)V
.locals 0
.line 1
check-cast p1, Lcom/vk/dto/newsfeed/entries/NewsEntry;
invoke-virtual {p0, p1}, Lcom/vk/newsfeed/holders/AdMarkHolder;->b(Lcom/vk/dto/newsfeed/entries/NewsEntry;)V
return-void
.end method
@@ -2860,7 +2860,17 @@
invoke-static {v2, v0}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/String;)V
.line 76
invoke-static {p2}, Lru/vtosters/hooks/PostsMenuHook;->isCustomButton(I)Z
move-result v3
if-eqz v3, :cond_20
invoke-static {p2, p3, v2}, Lru/vtosters/hooks/PostsMenuHook;->injectButtons(ILcom/vk/dto/newsfeed/entries/NewsEntry;Landroid/content/Context;)V
goto/16 :goto_1
:cond_20
invoke-interface {p0}, Lcom/vk/newsfeed/contracts/EntriesListContract;->v0()Ljava/lang/String;
move-result-object v3
@@ -3797,6 +3797,17 @@
if-eqz v4, :cond_6
invoke-static {p1}, Lru/vtosters/hooks/PostsMenuHook;->isCustomButton(I)Z
move-result v3
if-eqz v3, :cond_20
invoke-static {p1, v4, v0}, Lru/vtosters/hooks/PostsMenuHook;->injectButtons(ILcom/vk/dto/newsfeed/entries/NewsEntry;Landroid/content/Context;)V
goto/16 :goto_5
:cond_20
const/4 v1, 0x1
const/4 v2, 0x0