From a9509918d5e894a2c645363c951f9221bb1b0fb9 Mon Sep 17 00:00:00 2001 From: xtaodada Date: Mon, 6 May 2024 00:07:32 +0800 Subject: [PATCH] feat: remote page preview rules --- .../java/org/telegram/ui/ChatActivity.java | 20 +- .../java/org/telegram/ui/LaunchActivity.java | 2 + .../remote/PagePreviewRulesHelper.java | 231 ++++++++++++++++++ .../helpers/remote/PeerColorHelper.java | 1 - 4 files changed, 243 insertions(+), 11 deletions(-) create mode 100644 TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PagePreviewRulesHelper.java diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 7cc4500b18..e15eb10510 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -77,7 +77,6 @@ import android.text.style.ImageSpan; import android.text.style.URLSpan; import android.util.DisplayMetrics; -import android.util.Log; import android.util.Pair; import android.util.Property; import android.util.SparseArray; @@ -100,7 +99,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.DecelerateInterpolator; import android.view.inputmethod.EditorInfo; -import android.widget.DatePicker; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.HorizontalScrollView; @@ -169,13 +167,11 @@ import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.NotificationsController; -import org.telegram.messenger.PushListenerController; import org.telegram.messenger.R; import org.telegram.messenger.SecretChatHelper; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.SharedConfig; import org.telegram.messenger.SvgHelper; -import org.telegram.messenger.TranslateController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; @@ -274,7 +270,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.Stack; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; @@ -290,6 +285,7 @@ import tw.nekomimi.nekogram.NekoConfig; import tw.nekomimi.nekogram.NekoXConfig; import tw.nekomimi.nekogram.helpers.remote.EmojiHelper; +import tw.nekomimi.nekogram.helpers.remote.PagePreviewRulesHelper; import tw.nekomimi.nekogram.parts.MessageTransKt; import tw.nekomimi.nekogram.parts.PollTransUpdatesKt; import tw.nekomimi.nekogram.settings.NekoSettingsActivity; @@ -302,7 +298,6 @@ import tw.nekomimi.nekogram.utils.PGPUtil; import tw.nekomimi.nekogram.utils.ProxyUtil; import tw.nekomimi.nekogram.utils.TelegramUtil; -import tw.nekomimi.nekogram.utils.VibrateUtil; import xyz.nextalone.nagram.NaConfig; import xyz.nextalone.nagram.helper.DoubleTap; import xyz.nextalone.nagram.helper.MessageHelper; @@ -13375,10 +13370,15 @@ public void searchLinks(final CharSequence charSequence, final boolean force) { } final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); - if (textToCheck instanceof String) { - req.message = (String) textToCheck; - } else { - req.message = textToCheck.toString(); + // na: page preview rules + try { + req.message = PagePreviewRulesHelper.getInstance().doRegex(textToCheck); + } catch (Exception ignored) { + if (textToCheck instanceof String) { + req.message = (String) textToCheck; + } else { + req.message = textToCheck.toString(); + } } if (foundWebPage != null && req.message.equals(foundWebPage.displayedText)) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index e992ace036..1b11c9a3af 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -222,6 +222,7 @@ import tw.nekomimi.nekogram.InternalUpdater; import tw.nekomimi.nekogram.helpers.SettingsHelper; import tw.nekomimi.nekogram.helpers.remote.EmojiHelper; +import tw.nekomimi.nekogram.helpers.remote.PagePreviewRulesHelper; import tw.nekomimi.nekogram.helpers.remote.PeerColorHelper; import tw.nekomimi.nekogram.helpers.remote.UpdateHelper; import tw.nekomimi.nekogram.helpers.remote.WallpaperHelper; @@ -1052,6 +1053,7 @@ public void onViewDetachedFromWindow(View v) { EmojiHelper.getInstance().checkEmojiPacks(); WallpaperHelper.getInstance().checkWallPaper(); PeerColorHelper.getInstance().checkPeerColor(); + PagePreviewRulesHelper.getInstance().checkPagePreviewRules(); BackupAgent.requestBackup(this); RestrictedLanguagesSelectActivity.checkRestrictedLanguages(false); diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PagePreviewRulesHelper.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PagePreviewRulesHelper.java new file mode 100644 index 0000000000..2bbd56bce6 --- /dev/null +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PagePreviewRulesHelper.java @@ -0,0 +1,231 @@ +package tw.nekomimi.nekogram.helpers.remote; + +import android.text.TextUtils; +import android.util.Base64; + +import org.json.JSONException; +import org.json.JSONObject; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; +import org.telegram.tgnet.AbstractSerializedData; +import org.telegram.tgnet.SerializedData; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PagePreviewRulesHelper extends BaseRemoteHelper { + private static final String PAGE_PREVIEW_TAG = "pagepreview"; + private static volatile PagePreviewRulesHelper Instance; + private final ArrayList domains = new ArrayList<>(); + private final HashMap domainsMap = new HashMap<>(); + private boolean loading = false; + + public static PagePreviewRulesHelper getInstance() { + PagePreviewRulesHelper localInstance = Instance; + if (localInstance == null) { + synchronized (PagePreviewRulesHelper.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new PagePreviewRulesHelper(); + } + return localInstance; + } + } + return localInstance; + } + + @Override + protected void onError(String text, Delegate delegate) { + + } + + @Override + protected String getTag() { + return PAGE_PREVIEW_TAG; + } + + @Override + protected void onLoadSuccess(ArrayList responses, Delegate delegate) { + var tag = getTag(); + var json = responses.size() > 0 ? responses.get(0) : null; + if (json == null) { + preferences.edit() + .remove(tag + "_update_time") + .remove(tag) + .apply(); + return; + } + + try { + ArrayList domainInfo = new ArrayList<>(); + var array = json.getJSONArray("domains"); + + for (int i = 0; i < array.length(); i++) { + var obj = array.getJSONObject(i); + String domain = obj.getString("domain"); + var rules = obj.getJSONArray("rules"); + ArrayList domainRules = new ArrayList<>(); + for (int j = 0; j < rules.length(); j++) { + var obj1 = rules.getJSONObject(j); + var rule = new DomainRule( + obj1.getString("regex"), + obj1.getString("replace") + ); + domainRules.add(rule); + } + var info = new DomainInfo( + domain, + domainRules + ); + domainInfo.add(info); + } + + domains.clear(); + domains.addAll(domainInfo); + domainsMap.clear(); + for (DomainInfo info : domains) { + domainsMap.put(info.domain, info); + } + savePagePreviewRules(); + } catch (JSONException e) { + FileLog.e(e); + } + } + + public void loadPagePreviewRules() { + var tag = getTag(); + String list = preferences.getString(tag, ""); + domains.clear(); + domainsMap.clear(); + if (!TextUtils.isEmpty(list)) { + byte[] bytes = Base64.decode(list, Base64.DEFAULT); + SerializedData data = new SerializedData(bytes); + int count = data.readInt32(false); + for (int a = 0; a < count; a++) { + DomainInfo info = DomainInfo.deserialize(data); + domains.add(info); + domainsMap.put(info.domain, info); + } + data.cleanup(); + } + } + + public void savePagePreviewRules() { + var tag = getTag(); + SerializedData serializedData = new SerializedData(); + serializedData.writeInt32(domains.size()); + for (DomainInfo info : domains) { + info.serializeToStream(serializedData); + } + preferences.edit() + .putLong(tag + "_update_time", System.currentTimeMillis()) + .putString(tag, Base64.encodeToString(serializedData.toByteArray(), Base64.NO_WRAP | Base64.NO_PADDING)) + .apply(); + serializedData.cleanup(); + } + + public boolean needUpdate() { + var tag = getTag(); + long oldTime = preferences.getLong(tag + "_update_time", 0L); + long nowTime = System.currentTimeMillis(); + int TTL = 15 * 60; + return oldTime + TTL <= nowTime; + } + + public void checkPagePreviewRules() { + if (loading) { + return; + } + loading = true; + loadPagePreviewRules(); + if (needUpdate()) { + load(); + } + loading = false; + } + + public String doRegex(CharSequence textToCheck) { + String oldUrl; + if (textToCheck instanceof String) { + oldUrl = (String) textToCheck; + } else { + oldUrl = textToCheck.toString(); + } + String host = AndroidUtilities.getHostAuthority(oldUrl.toLowerCase()); + DomainInfo info = domainsMap.get(host); + if (info == null) { + return oldUrl; + } + for (DomainRule rule : info.rules) { + Pattern regex = rule.getRegexPattern(); + Matcher matcher = regex.matcher(oldUrl); + if (matcher.find()) { + oldUrl = matcher.replaceAll(rule.replace); + } + } + return oldUrl; + } + + public static class DomainRule { + public String regex; + public String replace; + + public DomainRule() {} + + public DomainRule(String regex, String replace) { + this.regex = regex; + this.replace = replace; + } + + public Pattern getRegexPattern() { + return Pattern.compile(regex); + } + + public static DomainRule deserialize(AbstractSerializedData stream) { + DomainRule domainRule = new DomainRule(); + domainRule.regex = stream.readString(false); + domainRule.replace = stream.readString(false); + return domainRule; + } + + public void serializeToStream(AbstractSerializedData serializedData) { + serializedData.writeString(regex); + serializedData.writeString(replace); + } + } + + public static class DomainInfo { + public String domain; + public ArrayList rules; + + public DomainInfo() {} + + public DomainInfo(String domain, ArrayList rules) { + this.domain = domain; + this.rules = rules; + } + + public static DomainInfo deserialize(AbstractSerializedData stream) { + DomainInfo domainInfo = new DomainInfo(); + domainInfo.domain = stream.readString(false); + int count = stream.readInt32(false); + ArrayList rules = new ArrayList<>(); + for (int a = 0; a < count; a++) { + DomainRule rule = DomainRule.deserialize(stream); + rules.add(rule); + } + domainInfo.rules = rules; + return domainInfo; + } + + public void serializeToStream(AbstractSerializedData serializedData) { + serializedData.writeString(domain); + serializedData.writeInt32(rules.size()); + for (DomainRule rule : rules) { + rule.serializeToStream(serializedData); + } + } + } +} diff --git a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PeerColorHelper.java b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PeerColorHelper.java index 59d1fecdc4..dac05978fa 100644 --- a/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PeerColorHelper.java +++ b/TMessagesProj/src/main/java/tw/nekomimi/nekogram/helpers/remote/PeerColorHelper.java @@ -88,7 +88,6 @@ protected void onLoadSuccess(ArrayList responses, Delegate delegate) savePeerColorInfo(); } catch (JSONException e) { FileLog.e(e); - delegate.onTLResponse(null, e.getLocalizedMessage()); } }