diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 7e882ce4f..f852e0e8a 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -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 ; public ; public (...); diff --git a/app/src/main/java/com/vk/medianative/MediaNative.java b/app/src/main/java/com/vk/medianative/MediaNative.java index 9821748e8..a3c6b0aab 100644 --- a/app/src/main/java/com/vk/medianative/MediaNative.java +++ b/app/src/main/java/com/vk/medianative/MediaNative.java @@ -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(); } diff --git a/app/src/main/java/com/vk/newsfeed/holders/AdMarkHolder.java b/app/src/main/java/com/vk/newsfeed/holders/AdMarkHolder.java new file mode 100644 index 000000000..99aa8ccee --- /dev/null +++ b/app/src/main/java/com/vk/newsfeed/holders/AdMarkHolder.java @@ -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 { + 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(); + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/hooks/NewsfeedHook.java b/app/src/main/java/ru/vtosters/hooks/NewsfeedHook.java index 874a65503..baa4bafa8 100644 --- a/app/src/main/java/ru/vtosters/hooks/NewsfeedHook.java +++ b/app/src/main/java/ru/vtosters/hooks/NewsfeedHook.java @@ -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 postIds = PostService.getPostIdsByOwnerId((long) ownerid, 0L); - PostsPreferences.saveGroupSpecifiedPosts(postIds, (long) ownerid); + if (PostsPreferences.isGroupAd(ownerid) || VotesPreferences.isGroupAd(ownerid)) { + if (VotesPreferences.isEnabled()) { + Map> postIds = VotesService.getPostIdsByOwnerId((long) ownerid, 0L); + VotesPreferences.saveGroupSpecifiedPosts(postIds.get("vote"), (long) ownerid); + PostsPreferences.saveGroupSpecifiedPosts(postIds.get("prod"), (long) ownerid); + } else { + List 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("Этот пост помечен как рекламный"); + } + } } }); } diff --git a/app/src/main/java/ru/vtosters/hooks/PostsMenuHook.java b/app/src/main/java/ru/vtosters/hooks/PostsMenuHook.java new file mode 100644 index 000000000..8d10b3e04 --- /dev/null +++ b/app/src/main/java/ru/vtosters/hooks/PostsMenuHook.java @@ -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; + } +} diff --git a/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java b/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java index 699156ece..797bb14f1 100644 --- a/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java +++ b/app/src/main/java/ru/vtosters/hooks/music/injectors/CatalogJsonInjector.java @@ -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()); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/hooks/other/Preferences.java b/app/src/main/java/ru/vtosters/hooks/other/Preferences.java index ee621216a..0f743c448 100644 --- a/app/src/main/java/ru/vtosters/hooks/other/Preferences.java +++ b/app/src/main/java/ru/vtosters/hooks/other/Preferences.java @@ -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(); diff --git a/app/src/main/java/ru/vtosters/lite/downloaders/messages/MessagesDownloader.java b/app/src/main/java/ru/vtosters/lite/downloaders/messages/MessagesDownloader.java index 918e57900..1e3617055 100644 --- a/app/src/main/java/ru/vtosters/lite/downloaders/messages/MessagesDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/downloaders/messages/MessagesDownloader.java @@ -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 users = new SparseArray<>(); parseUsers(users, obj.optJSONArray("profiles"), false); diff --git a/app/src/main/java/ru/vtosters/lite/foaf/FoafBase.java b/app/src/main/java/ru/vtosters/lite/foaf/FoafBase.java index 1f2255a22..32e1a47bb 100644 --- a/app/src/main/java/ru/vtosters/lite/foaf/FoafBase.java +++ b/app/src/main/java/ru/vtosters/lite/foaf/FoafBase.java @@ -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()); diff --git a/app/src/main/java/ru/vtosters/lite/music/Genius.java b/app/src/main/java/ru/vtosters/lite/music/Genius.java index 04ef54211..53cbdec95 100644 --- a/app/src/main/java/ru/vtosters/lite/music/Genius.java +++ b/app/src/main/java/ru/vtosters/lite/music/Genius.java @@ -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(); } } -} +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java b/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java index 898a0d329..5a916c4c2 100644 --- a/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java +++ b/app/src/main/java/ru/vtosters/lite/music/LastFMScrobbler.java @@ -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; diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java b/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java index 6c50a8a1a..e68c6e200 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/MusicCacheImpl.java @@ -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, diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java b/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java index fb0b738f8..e13e2c1ce 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/db/MusicCacheDb.java @@ -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); diff --git a/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java b/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java index 9c86118d1..38f3c65ec 100644 --- a/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java +++ b/app/src/main/java/ru/vtosters/lite/music/cache/helpers/PlaylistHelper.java @@ -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() )); diff --git a/app/src/main/java/ru/vtosters/lite/music/converter/playlist/PlaylistConverter.java b/app/src/main/java/ru/vtosters/lite/music/converter/playlist/PlaylistConverter.java index 602dbc81b..139599d6d 100644 --- a/app/src/main/java/ru/vtosters/lite/music/converter/playlist/PlaylistConverter.java +++ b/app/src/main/java/ru/vtosters/lite/music/converter/playlist/PlaylistConverter.java @@ -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; diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/AudioGet.java b/app/src/main/java/ru/vtosters/lite/music/downloader/AudioGet.java index aea805d1a..a8e161a17 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/AudioGet.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/AudioGet.java @@ -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); } diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java b/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java index a1698a9be..06b49b095 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java @@ -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("[\\\\/:*?\"<>|]", ""); + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java index 76d0b84c7..76fa0d6a3 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/OtherFragment.java @@ -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; diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/SponsorPostFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/SponsorPostFragment.java index e47a1ae49..90bdc1146 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/SponsorPostFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/SponsorPostFragment.java @@ -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 diff --git a/app/src/main/java/ru/vtosters/lite/utils/OTAUtils.java b/app/src/main/java/ru/vtosters/lite/utils/OTAUtils.java index b3bc11e0d..a3643ff13 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/OTAUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/OTAUtils.java @@ -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(); } diff --git a/app/src/main/java/ru/vtosters/lite/utils/VTVerifications.java b/app/src/main/java/ru/vtosters/lite/utils/VTVerifications.java index 0e091ab45..dbbc6c305 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/VTVerifications.java +++ b/app/src/main/java/ru/vtosters/lite/utils/VTVerifications.java @@ -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) diff --git a/app/src/main/java/ru/vtosters/lite/utils/newsfeed/NewsFeedFiltersUtils.java b/app/src/main/java/ru/vtosters/lite/utils/newsfeed/NewsFeedFiltersUtils.java index d3109db8f..ad5dde97c 100644 --- a/app/src/main/java/ru/vtosters/lite/utils/newsfeed/NewsFeedFiltersUtils.java +++ b/app/src/main/java/ru/vtosters/lite/utils/newsfeed/NewsFeedFiltersUtils.java @@ -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 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); } diff --git a/app/src/main/java/ru/vtosters/sponsorpost/internal/Native.java b/app/src/main/java/ru/vtosters/sponsorpost/internal/Native.java new file mode 100644 index 000000000..65ffdf319 --- /dev/null +++ b/app/src/main/java/ru/vtosters/sponsorpost/internal/Native.java @@ -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(); +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/sponsorpost/internal/VotesPreferences.java b/app/src/main/java/ru/vtosters/sponsorpost/internal/VotesPreferences.java new file mode 100644 index 000000000..7cac8707e --- /dev/null +++ b/app/src/main/java/ru/vtosters/sponsorpost/internal/VotesPreferences.java @@ -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 posts) { + preferences.edit() + .putStringSet("posts", new HashSet<>(posts)) + .apply(); + } + + public static void saveGroupsIds(List ids) { + preferences.edit() + .putStringSet("groupIds", new HashSet<>(ids)) + .apply(); + } + + public static void saveGroupSpecifiedPosts(List postsIds, Long ownerId) { + Set 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 currentStringSet = preferences.getStringSet("posts", new HashSet<>()); + Set 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 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 hasSpecifiedGroupPosts = preferences.getStringSet(ownerId + "_posts", new HashSet<>()); + Set hasPost = preferences.getStringSet("posts", new HashSet<>()); + + return hasPost.contains(ownerId + "_" + postId) || hasSpecifiedGroupPosts.contains(ownerId + "_" + postId); + } else { + return false; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/sponsorpost/internal/VotesService.java b/app/src/main/java/ru/vtosters/sponsorpost/internal/VotesService.java new file mode 100644 index 000000000..075917396 --- /dev/null +++ b/app/src/main/java/ru/vtosters/sponsorpost/internal/VotesService.java @@ -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> 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> 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 prodList = IntStream.range(0, prodBase.length()) + .mapToObj(prodBase::optString) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + List 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> 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> 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); + } + } +} diff --git a/app/src/main/java/ru/vtosters/sponsorpost/services/FilterService.java b/app/src/main/java/ru/vtosters/sponsorpost/services/FilterService.java index 9eaa07305..5caa2438b 100644 --- a/app/src/main/java/ru/vtosters/sponsorpost/services/FilterService.java +++ b/app/src/main/java/ru/vtosters/sponsorpost/services/FilterService.java @@ -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 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()); } diff --git a/app/src/main/java/ru/vtosters/sponsorpost/services/PostService.java b/app/src/main/java/ru/vtosters/sponsorpost/services/PostService.java index 823c06080..e50f91d79 100644 --- a/app/src/main/java/ru/vtosters/sponsorpost/services/PostService.java +++ b/app/src/main/java/ru/vtosters/sponsorpost/services/PostService.java @@ -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 getAllPostsIds() { + public static List 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()); diff --git a/app/src/main/java/ru/vtosters/sponsorpost/utils/FiltersPreferences.java b/app/src/main/java/ru/vtosters/sponsorpost/utils/FiltersPreferences.java index a8ff8bf46..8b9d2a519 100644 --- a/app/src/main/java/ru/vtosters/sponsorpost/utils/FiltersPreferences.java +++ b/app/src/main/java/ru/vtosters/sponsorpost/utils/FiltersPreferences.java @@ -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(); diff --git a/app/src/main/java/ru/vtosters/sponsorpost/utils/GzipDecompressor.java b/app/src/main/java/ru/vtosters/sponsorpost/utils/GzipDecompressor.java index b54ca68e9..27042fe60 100644 --- a/app/src/main/java/ru/vtosters/sponsorpost/utils/GzipDecompressor.java +++ b/app/src/main/java/ru/vtosters/sponsorpost/utils/GzipDecompressor.java @@ -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(); + } + } } \ No newline at end of file diff --git a/app/src/main/java/ru/vtosters/sponsorpost/utils/PostsPreferences.java b/app/src/main/java/ru/vtosters/sponsorpost/utils/PostsPreferences.java index 7fe438609..fe11ac49a 100644 --- a/app/src/main/java/ru/vtosters/sponsorpost/utils/PostsPreferences.java +++ b/app/src/main/java/ru/vtosters/sponsorpost/utils/PostsPreferences.java @@ -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 posts) { Set stringSet = posts.stream() .map(post -> post.getOwnerId() + "_" + post.getPostId()) @@ -40,7 +48,13 @@ public class PostsPreferences { .apply(); } - public static void saveGroupSpecifiedPosts(List postsIds, Long ownerId) { + public static void savePostsStr(List posts) { + preferences.edit() + .putStringSet("posts", new HashSet<>(posts)) + .apply(); + } + + public static void saveGroupSpecifiedPosts(List postsIds, Long ownerId) { Set stringSet = postsIds.stream() .map(post -> ownerId + "_" + post) .collect(Collectors.toSet()); @@ -50,7 +64,7 @@ public class PostsPreferences { .apply(); } - public static void saveGroupsIds(List ids) { + public static void saveGroupsIds(List ids) { Set 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 hasSpecifiedGroupPosts = preferences.getStringSet(ownerId + "_posts", new HashSet<>()); diff --git a/app/src/main/java/ru/vtosters/sponsorpost/utils/Updates.java b/app/src/main/java/ru/vtosters/sponsorpost/utils/Updates.java index 734e8f291..d59656a66 100644 --- a/app/src/main/java/ru/vtosters/sponsorpost/utils/Updates.java +++ b/app/src/main/java/ru/vtosters/sponsorpost/utils/Updates.java @@ -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 posts = PostService.getPosts(weekAgo); - List groupIds = PostService.getOwnerIds(); + if (VotesPreferences.isEnabled()) { + Map> posts = VotesService.getPosts(weekAgo / 1000); + Map> 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 posts = PostService.getAllPostsIds(weekAgo / 1000); + List groupIds = PostService.getOwnerIds(); + + if (!posts.isEmpty()) { + PostsPreferences.savePostsStr(posts); + } + + if (!groupIds.isEmpty()) { + PostsPreferences.saveGroupsIds(groupIds); + } } } } -} +} \ No newline at end of file diff --git a/smali/smali_classes2/com/vk/discover/DiscoverFragment.smali b/smali/smali_classes2/com/vk/discover/DiscoverFragment.smali index dc20e63e3..d695ef65d 100644 --- a/smali/smali_classes2/com/vk/discover/DiscoverFragment.smali +++ b/smali/smali_classes2/com/vk/discover/DiscoverFragment.smali @@ -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 diff --git a/smali/smali_classes3/com/vk/newsfeed/NewsEntryActionsMenuBuilder.smali b/smali/smali_classes3/com/vk/newsfeed/NewsEntryActionsMenuBuilder.smali index aa26d4ffd..be72808a8 100644 --- a/smali/smali_classes3/com/vk/newsfeed/NewsEntryActionsMenuBuilder.smali +++ b/smali/smali_classes3/com/vk/newsfeed/NewsEntryActionsMenuBuilder.smali @@ -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 diff --git a/smali/smali_classes3/com/vk/newsfeed/PostViewActionsMenuBuilder.smali b/smali/smali_classes3/com/vk/newsfeed/PostViewActionsMenuBuilder.smali index 5e00df72f..1d67e03dd 100644 --- a/smali/smali_classes3/com/vk/newsfeed/PostViewActionsMenuBuilder.smali +++ b/smali/smali_classes3/com/vk/newsfeed/PostViewActionsMenuBuilder.smali @@ -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 diff --git a/smali/smali_classes3/com/vk/newsfeed/holders/AdMarkHolder.smali b/smali/smali_classes3/com/vk/newsfeed/holders/AdMarkHolder.smali deleted file mode 100644 index aa7e38cba..000000000 --- a/smali/smali_classes3/com/vk/newsfeed/holders/AdMarkHolder.smali +++ /dev/null @@ -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 (Landroid/view/ViewGroup;)V - .locals 3 - - const v0, 0x7f0d0307 - - .line 1 - invoke-direct {p0, v0, p1}, Lcom/vk/newsfeed/holders/BaseNewsEntryHolder;->(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 diff --git a/smali/smali_classes3/com/vk/newsfeed/presenters/EntriesListPresenter.smali b/smali/smali_classes3/com/vk/newsfeed/presenters/EntriesListPresenter.smali index c89e77057..c5002acd6 100644 --- a/smali/smali_classes3/com/vk/newsfeed/presenters/EntriesListPresenter.smali +++ b/smali/smali_classes3/com/vk/newsfeed/presenters/EntriesListPresenter.smali @@ -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 diff --git a/smali/smali_classes4/com/vk/wall/post/PostViewPresenter.smali b/smali/smali_classes4/com/vk/wall/post/PostViewPresenter.smali index 8d3f40abb..50043d48c 100644 --- a/smali/smali_classes4/com/vk/wall/post/PostViewPresenter.smali +++ b/smali/smali_classes4/com/vk/wall/post/PostViewPresenter.smali @@ -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