1
0
mirror of https://github.com/areteruhiro/LIME-beta-hiro.git synced 2025-02-05 21:11:39 +09:00

Merge branch 'master' into patch-30

This commit is contained in:
Syuugo 2024-10-26 17:11:20 +09:00 committed by GitHub
commit 5f4287024f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 657 additions and 14 deletions

View File

@ -33,7 +33,8 @@ public class LimeOptions {
public Option blockTracking = new Option("block_tracking", R.string.switch_block_tracking, false);
public Option stopVersionCheck = new Option("stop_version_check", R.string.switch_stop_version_check, false);
public Option outputCommunication = new Option("output_communication", R.string.switch_output_communication, false);
public Option Archived = new Option("Archived_message", R.string.switch_archived, false);
public Option archived = new Option("archived_message", R.string.switch_archived, false);
public Option callTone = new Option("call_tone", R.string.call_tone, false);
public Option[] options = {
removeVoom,
@ -51,11 +52,12 @@ public class LimeOptions {
openInBrowser,
preventMarkAsRead,
preventUnsendMessage,
Archived,
archived,
sendMuteMessage,
removeKeepUnread,
blockTracking,
stopVersionCheck,
outputCommunication
outputCommunication,
callTone
};
}

View File

@ -30,9 +30,11 @@ import io.github.chipppppppppp.lime.hooks.RemoveFlexibleContents;
import io.github.chipppppppppp.lime.hooks.RemoveIconLabels;
import io.github.chipppppppppp.lime.hooks.RemoveIcons;
import io.github.chipppppppppp.lime.hooks.RemoveReplyMute;
import io.github.chipppppppppp.lime.hooks.Ringtone;
import io.github.chipppppppppp.lime.hooks.SendMuteMessage;
import io.github.chipppppppppp.lime.hooks.SpoofAndroidId;
import io.github.chipppppppppp.lime.hooks.SpoofUserAgent;
import io.github.chipppppppppp.lime.hooks.UnsentCap;
public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResources, IXposedHookZygoteInit {
public static String modulePath;
@ -63,7 +65,9 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
new BlockTracking(),
new ModifyResponse(),
new OutputRequest(),
new Archived()
new Archived(),
new Ringtone(),
new UnsentCap()
};
public void handleLoadPackage(@NonNull XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {

View File

@ -27,7 +27,7 @@ public class Archived implements IHook {
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!limeOptions.Archived.checked) return;
if (!limeOptions.archived.checked) return;
XposedBridge.hookAllMethods(Application.class, "onCreate", new XC_MethodHook() {
@Override
@ -50,7 +50,7 @@ public class Archived implements IHook {
}
private void hookMessageDeletion(XC_LoadPackage.LoadPackageParam loadPackageParam, Context context, SQLiteDatabase db, Context moduleContext) {
if (!limeOptions.Archived.checked) return;
if (!limeOptions.archived.checked) return;
try {
XposedBridge.hookAllMethods(

View File

@ -12,6 +12,8 @@ import io.github.chipppppppppp.lime.LimeOptions;
public class RemoveFlexibleContents implements IHook {
int recommendationResId, serviceNameResId, notificationResId;
int serviceRowContainerResId, serviceIconResId, serviceCarouselResId;
int serviceTitleBackgroundResId, serviceTitleResId, serviceSeeMoreResId, serviceSeeMoreBadgeResId;
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
@ -25,6 +27,13 @@ public class RemoveFlexibleContents implements IHook {
recommendationResId = context.getResources().getIdentifier("home_tab_contents_recommendation_placement", "id", context.getPackageName());
serviceNameResId = context.getResources().getIdentifier("home_tab_service_name", "id", context.getPackageName());
notificationResId = context.getResources().getIdentifier("notification_hub_row_rolling_view_group", "id", context.getPackageName());
serviceRowContainerResId = context.getResources().getIdentifier("service_row_container", "id", context.getPackageName());
serviceIconResId = context.getResources().getIdentifier("home_tab_service_icon", "id", context.getPackageName());
serviceCarouselResId = context.getResources().getIdentifier("home_tab_service_carousel", "id", context.getPackageName());
serviceTitleBackgroundResId = context.getResources().getIdentifier("home_tab_service_title_background", "id", context.getPackageName());
serviceTitleResId = context.getResources().getIdentifier("home_tab_service_title", "id", context.getPackageName());
serviceSeeMoreResId = context.getResources().getIdentifier("home_tab_service_see_more", "id", context.getPackageName());
serviceSeeMoreBadgeResId = context.getResources().getIdentifier("home_tab_service_see_more_badge", "id", context.getPackageName());
}
}
);
@ -33,22 +42,37 @@ public class RemoveFlexibleContents implements IHook {
View.class,
"onAttachedToWindow",
new XC_MethodHook() {
View view;
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
view = (View) param.thisObject;
if (limeOptions.removeRecommendation.checked && view.getId() == recommendationResId
|| limeOptions.removeServiceLabels.checked && view.getId() == serviceNameResId) {
View view = (View) param.thisObject;
int viewId = view.getId();
//String resourceName = getResourceName(view.getContext(), viewId);
//XposedBridge.log("View ID: " + viewId + ", Resource Name: " + resourceName);
if (limeOptions.removeRecommendation.checked && viewId == recommendationResId
|| limeOptions.removeServiceLabels.checked && viewId == serviceNameResId
|| viewId == serviceRowContainerResId
|| viewId == serviceIconResId
|| viewId == serviceCarouselResId
|| viewId == serviceTitleBackgroundResId
|| viewId == serviceTitleResId
|| viewId == serviceSeeMoreResId
|| viewId == serviceSeeMoreBadgeResId) {
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = 0;
view.setLayoutParams(layoutParams);
view.setVisibility(View.GONE);
} else if (view.getId() == notificationResId) {
} else if (viewId == notificationResId) {
((View) view.getParent()).setVisibility(View.GONE);
}
}
}
);
}
/*
private String getResourceName(Context context, int resourceId) {
return context.getResources().getResourceEntryName(resourceId);
}
*/
}

View File

@ -0,0 +1,61 @@
package io.github.chipppppppppp.lime.hooks;
import android.app.AndroidAppHelper;
import android.content.Context;
import android.media.RingtoneManager;
import android.net.Uri;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import io.github.chipppppppppp.lime.LimeOptions;
public class Ringtone implements IHook {
private android.media.Ringtone ringtone = null;
private boolean isPlaying = false;
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!limeOptions.callTone.checked) return;
XposedBridge.hookAllMethods(
loadPackageParam.classLoader.loadClass(Constants.RESPONSE_HOOK.className),
Constants.RESPONSE_HOOK.methodName,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String paramValue = param.args[1].toString();
if (paramValue.contains("type:NOTIFIED_RECEIVED_CALL,") && !isPlaying) {
Context context = AndroidAppHelper.currentApplication().getApplicationContext();
if (context != null) {
Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
ringtone = RingtoneManager.getRingtone(context, ringtoneUri);
ringtone.play();
isPlaying = true;
}
if (paramValue.contains("RESULT=REJECTED,") ||
paramValue.contains("RESULT=REJECTED,")) {
if (ringtone != null && ringtone.isPlaying()) {
ringtone.stop();
isPlaying = false;
}
}
}
}
});
Class<?> voIPBaseFragmentClass = loadPackageParam.classLoader.loadClass("com.linecorp.voip2.common.base.VoIPBaseFragment");
XposedBridge.hookAllMethods(voIPBaseFragmentClass, "onCreate", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (ringtone != null && ringtone.isPlaying()) {
ringtone.stop();
isPlaying = false;
}
}
});
}
}

View File

@ -0,0 +1,493 @@
package io.github.chipppppppppp.lime.hooks;
import android.app.AlertDialog;
import android.app.AndroidAppHelper;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.HorizontalScrollView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import io.github.chipppppppppp.lime.LimeOptions;
import io.github.chipppppppppp.lime.R;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class UnsentCap implements IHook {
public static final String Main_file = "unsent_capture.txt";
public static final String Main_backup = "capture_backup.txt";
public static final String Unresolved_Ids = "Unresolved_Ids.txt";
SQLiteDatabase db1 = null;
SQLiteDatabase db2 = null;
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!limeOptions.preventUnsendMessage.checked) return;
XposedBridge.hookAllConstructors(
loadPackageParam.classLoader.loadClass("jp.naver.line.android.common.view.listview.PopupListView"),
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ViewGroup viewGroup = (ViewGroup) param.thisObject;
Context appContext = viewGroup.getContext();
Context moduleContext = AndroidAppHelper.currentApplication().createPackageContext(
"io.github.chipppppppppp.lime", Context.CONTEXT_IGNORE_SECURITY);
RelativeLayout container = new RelativeLayout(appContext);
container.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
Button openFileButton = new Button(appContext);
openFileButton.setText(moduleContext.getResources().getString(R.string.confirm_messages));
openFileButton.setTextSize(12);
openFileButton.setTextColor(Color.BLACK);
openFileButton.setId(View.generateViewId());
RelativeLayout.LayoutParams buttonParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
buttonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
container.addView(openFileButton, buttonParams);
Button clearFileButton = new Button(appContext);
clearFileButton.setText(moduleContext.getResources().getString(R.string.delete_messages));
clearFileButton.setTextSize(12);
clearFileButton.setTextColor(Color.RED);
clearFileButton.setId(View.generateViewId());
RelativeLayout.LayoutParams clearButtonParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
clearButtonParams.addRule(RelativeLayout.BELOW, openFileButton.getId());
clearButtonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
container.addView(clearFileButton, clearButtonParams);
openFileButton.setOnClickListener(v -> {
File backupFile = new File(appContext.getFilesDir(), Main_backup);
if (!backupFile.exists()) {
try {
backupFile.createNewFile();
} catch (IOException ignored) {
Toast.makeText(appContext, moduleContext.getResources().getString(R.string.file_creation_failed), Toast.LENGTH_SHORT).show();
return;
}
}
if (backupFile.length() > 0) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(backupFile)))) {
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(appContext);
ScrollView verticalScrollView = new ScrollView(appContext);
TextView textView = new TextView(appContext);
textView.setText(output.toString());
textView.setMaxLines(Integer.MAX_VALUE);
textView.setHorizontallyScrolling(true);
textView.setHorizontalScrollBarEnabled(true);
horizontalScrollView.addView(textView);
verticalScrollView.addView(horizontalScrollView);
new AlertDialog.Builder(appContext)
.setTitle(moduleContext.getResources().getString(R.string.backup))
.setView(verticalScrollView)
.setPositiveButton(moduleContext.getResources().getString(R.string.positive_button), null)
.create()
.show();
} catch (IOException ignored) {
Toast.makeText(appContext, moduleContext.getResources().getString(R.string.failed_read_backup_file, Main_backup), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(appContext, moduleContext.getResources().getString(R.string.no_backup_found), Toast.LENGTH_SHORT).show();
}
});
clearFileButton.setOnClickListener(v -> new AlertDialog.Builder(appContext)
.setTitle(moduleContext.getResources().getString(R.string.confirm))
.setMessage(moduleContext.getResources().getString(R.string.confirm_delete))
.setPositiveButton(moduleContext.getResources().getString(R.string.yes), (dialog, which) -> {
File backupFile = new File(appContext.getFilesDir(), Main_backup);
if (backupFile.exists()) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(backupFile))) {
writer.write("");
Toast.makeText(appContext, moduleContext.getResources().getString(R.string.file_content_deleted), Toast.LENGTH_SHORT).show();
} catch (IOException ignored) {
Toast.makeText(appContext, moduleContext.getResources().getString(R.string.file_delete_failed), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(appContext, moduleContext.getResources().getString(R.string.file_not_found), Toast.LENGTH_SHORT).show();
}
})
.setNegativeButton(moduleContext.getResources().getString(R.string.no), null)
.create()
.show());
((ListView) viewGroup.getChildAt(0)).addFooterView(container);
}
}
);
XposedHelpers.findAndHookMethod(
"com.linecorp.line.chatlist.view.fragment.ChatListPageFragment",
loadPackageParam.classLoader, "onCreateView",
LayoutInflater.class, ViewGroup.class, android.os.Bundle.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context moduleContext = AndroidAppHelper.currentApplication().createPackageContext(
"io.github.chipppppppppp.lime", Context.CONTEXT_IGNORE_SECURITY);
View rootView = (View) param.getResult();
Context context = rootView.getContext();
File originalFile = new File(context.getFilesDir(), Main_file);
if (!originalFile.exists()) {
try {
originalFile.createNewFile();
} catch (IOException ignored) {
Toast.makeText(context, moduleContext.getResources().getString(R.string.file_creation_failed), Toast.LENGTH_SHORT).show();
return;
}
}
if (originalFile.length() > 0) {
int lineCount = countLinesInFile(originalFile);
if (lineCount > 0) {
Button button = new Button(context);
button.setText(Integer.toString(lineCount));
button.setId(View.generateViewId());
button.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
button.setOnClickListener(v -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(originalFile)))) {
StringBuilder output = new StringBuilder();
boolean showToast = false;
SharedPreferences prefs = context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
boolean messageShown = prefs.getBoolean("messageShown", false);
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("No content") || line.contains("No name")) {
if (!messageShown) {
showToast = true;
prefs.edit().putBoolean("messageShown", true).apply();
}
continue;
}
output.append(line).append("\n");
}
if (showToast) {
Toast.makeText(context, moduleContext.getResources().getString(R.string.no_get_restart_app), Toast.LENGTH_SHORT).show();
}
HorizontalScrollView horizontalScrollView = new HorizontalScrollView(context);
ScrollView verticalScrollView = new ScrollView(context);
TextView textView = new TextView(context);
textView.setText(output.toString());
textView.setMaxLines(Integer.MAX_VALUE);
textView.setHorizontallyScrolling(true);
textView.setHorizontalScrollBarEnabled(true);
horizontalScrollView.addView(textView);
verticalScrollView.addView(horizontalScrollView);
new AlertDialog.Builder(context)
.setTitle(moduleContext.getResources().getString(R.string.deleted_messages))
.setView(verticalScrollView)
.setPositiveButton(moduleContext.getResources().getString(R.string.positive_button), (dialog, which) -> {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(new File(context.getFilesDir(), Main_backup), true))) {
writer.write(output.toString());
new BufferedWriter(new FileWriter(originalFile)).close();
Toast.makeText(context, moduleContext.getResources().getString(R.string.content_moved_to_backup), Toast.LENGTH_SHORT).show();
prefs.edit().putBoolean("messageShown", false).apply();
} catch (IOException ignored) {
Toast.makeText(context, moduleContext.getResources().getString(R.string.file_move_failed), Toast.LENGTH_SHORT).show();
}
if (button.getParent() instanceof ViewGroup) {
((ViewGroup) button.getParent()).removeView(button);
}
})
.create()
.show();
} catch (IOException ignored) {
Toast.makeText(context, moduleContext.getResources().getString(R.string.failed_read_backup_file, Main_backup), Toast.LENGTH_SHORT).show();
}
});
if (rootView instanceof ViewGroup) {
((ViewGroup) rootView).addView(button);
}
}
}
}
}
);
XposedBridge.hookAllMethods(Application.class, "onCreate", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Application appContext = (Application) param.thisObject;
if (appContext == null) {
XposedBridge.log("appContext is null!");
return;
}
Context moduleContext;
try {
moduleContext = appContext.createPackageContext(
"io.github.chipppppppppp.lime", Context.CONTEXT_IGNORE_SECURITY);
} catch (PackageManager.NameNotFoundException e) {
XposedBridge.log("Failed to create package context: " + e.getMessage());
return;
}
File dbFile1 = appContext.getDatabasePath("naver_line");
File dbFile2 = appContext.getDatabasePath("contact");
if (!dbFile1.exists() || !dbFile2.exists()) return;
SQLiteDatabase.OpenParams.Builder builder1 = new SQLiteDatabase.OpenParams.Builder().addOpenFlags(SQLiteDatabase.OPEN_READWRITE);
SQLiteDatabase db1 = SQLiteDatabase.openDatabase(dbFile1, builder1.build());
SQLiteDatabase.OpenParams.Builder builder2 = new SQLiteDatabase.OpenParams.Builder().addOpenFlags(SQLiteDatabase.OPEN_READWRITE);
SQLiteDatabase db2 = SQLiteDatabase.openDatabase(dbFile2, builder2.build());
hookMessageDeletion(loadPackageParam, appContext, db1, db2);
resolveUnresolvedIds(loadPackageParam, appContext, db1, db2, moduleContext);
}
});
}
private String queryDatabase(SQLiteDatabase db, String query, String... selectionArgs) {
if (db == null) {
XposedBridge.log("Database is not initialized.");
return null;
}
Cursor cursor = db.rawQuery(query, selectionArgs);
String result = null;
if (cursor.moveToFirst()) result = cursor.getString(0);
cursor.close();
return result;
}
private int countLinesInFile(File file) {
int count = 0;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
String line;
while ((line = reader.readLine()) != null) {
if (!(line.contains("No content") || line.contains("No name"))) count++;
}
} catch (IOException e) {
e.printStackTrace();
}
return count;
}
private void hookMessageDeletion(XC_LoadPackage.LoadPackageParam loadPackageParam, Context context, SQLiteDatabase db1, SQLiteDatabase db2) {
try {
XposedBridge.hookAllMethods(
loadPackageParam.classLoader.loadClass(Constants.RESPONSE_HOOK.className),
Constants.RESPONSE_HOOK.methodName,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context appContext = AndroidAppHelper.currentApplication();
if (appContext == null) return;
File dbFile = appContext.getDatabasePath("naver_line");
if (!dbFile.exists()) return;
SQLiteDatabase.OpenParams dbParams = new SQLiteDatabase.OpenParams.Builder()
.addOpenFlags(SQLiteDatabase.OPEN_READWRITE)
.build();
SQLiteDatabase db = SQLiteDatabase.openDatabase(dbFile, dbParams);
String paramValue = param.args[1].toString();
if (!paramValue.contains("type:NOTIFIED_DESTROY_MESSAGE,")) {
if (db != null) db.close(); // 条件を満たさない場合はデータベースをクローズ
return;
}
Context moduleContext = appContext.createPackageContext(
"io.github.chipppppppppp.lime", Context.CONTEXT_IGNORE_SECURITY);
processMessage(paramValue, moduleContext, db1, db2, context);
if (db != null) db.close();
}
});
} catch (ClassNotFoundException ignored ) {
}
}
private void processMessage(String paramValue, Context moduleContext, SQLiteDatabase db1, SQLiteDatabase db2, Context context) {
String unresolvedFilePath = context.getFilesDir() + "/" + Unresolved_Ids;
String[] operations = paramValue.split("Operation\\(");
for (String operation : operations) {
if (operation.trim().isEmpty()) continue;
String revision = null, createdTime = null, type = null, from = null, to = null, param12 = null, param22 = null, operationContent = null, serverId = null, talkId = null;
String[] parts = operation.split(",");
for (String part : parts) {
part = part.trim();
if (part.startsWith("param1:")) talkId = part.substring("param1:".length()).trim();
else if (part.startsWith("param2:")) serverId = part.substring("param2:".length()).trim();
else if (part.startsWith("revision:")) revision = part.substring("revision:".length()).trim();
else if (part.startsWith("createdTime:")) createdTime = part.substring("createdTime:".length()).trim();
else if (part.startsWith("type:")) type = part.substring("type:".length()).trim();
else if (part.startsWith("from:")) from = part.substring("from:".length()).trim();
else if (part.startsWith("to:")) to = part.substring("to:".length()).trim();
else if (part.startsWith("contentMetadata:")) param12 = part.substring("contentMetadata:".length()).trim();
else if (part.startsWith("operationContent:")) operationContent = part.substring("operationContent:".length()).trim();
}
if (serverId == null || talkId == null) continue;
String content = queryDatabase(db1, "SELECT content FROM chat_history WHERE server_id=?", serverId);
String timeEpochStr = queryDatabase(db1, "SELECT created_time FROM chat_history WHERE server_id=?", serverId);
String timeFormatted = formatMessageTime(timeEpochStr);
String groupName = queryDatabase(db1, "SELECT name FROM groups WHERE id=?", talkId);
String media = queryDatabase(db1, "SELECT attachement_type FROM chat_history WHERE server_id=?", serverId);
String talkName = queryDatabase(db2, "SELECT profile_name FROM contacts WHERE mid=?", talkId);
String name = (groupName != null ? groupName : (talkName != null ? talkName : "No Name" + ":" + "talkId" + talkId));
if (timeEpochStr == null) saveUnresolvedIds(serverId, talkId, unresolvedFilePath);
String from_mid = null, sender_name = null;
if (groupName != null) {
from_mid = queryDatabase(db1, "SELECT from_mid FROM chat_history WHERE server_id=?", serverId);
if (from_mid != null) sender_name = queryDatabase(db2, "SELECT profile_name FROM contacts WHERE mid=?", from_mid);
}
if (sender_name != null) name = groupName + ": " + sender_name;
String mediaDescription = "";
if (media != null) {
switch (media) {
case "7": mediaDescription = moduleContext.getResources().getString(R.string.sticker); break;
case "1": mediaDescription = moduleContext.getResources().getString(R.string.picture); break;
case "2": mediaDescription = moduleContext.getResources().getString(R.string.video); break;
}
}
String logEntry = (timeFormatted != null ? timeFormatted : "No Time: ")
+ name
+ ": " + ((content != null) ? content : "No content:" + serverId)
+ mediaDescription;
File fileToWrite = new File(context.getFilesDir(), Main_file);
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileToWrite, true))) {
writer.write(logEntry);
writer.newLine();
} catch (IOException e) {
XposedBridge.log("IOException occurred while writing to file: " + e.getMessage());
}
}
}
private void saveUnresolvedIds(String serverId, String talkId, String filePath) {
String newEntry = "serverId:" + serverId + ",talkId:" + talkId;
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.equals(newEntry)) return;
}
} catch (IOException ignored) {}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
writer.write(newEntry);
writer.newLine();
} catch (IOException ignored) {}
}
private void resolveUnresolvedIds(XC_LoadPackage.LoadPackageParam loadPackageParam, Context context, SQLiteDatabase db1, SQLiteDatabase db2, Context moduleContext) {
String unresolvedFilePath = context.getFilesDir() + "/" + Unresolved_Ids;
File unresolvedFile = new File(unresolvedFilePath);
File testFile = new File(context.getFilesDir(), Main_file);
if (!unresolvedFile.exists()) return;
try (BufferedReader reader = new BufferedReader(new FileReader(unresolvedFile));
BufferedWriter testWriter = new BufferedWriter(new FileWriter(testFile, true))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
String serverId = parts[0].split(":")[1];
String talkId = parts[1].split(":")[1];
String content = queryDatabase(db1, "SELECT content FROM chat_history WHERE server_id=?", serverId);
if (content == null) continue;
String timeEpochStr = queryDatabase(db1, "SELECT created_time FROM chat_history WHERE server_id=?", serverId);
String timeFormatted = formatMessageTime(timeEpochStr);
String groupName = queryDatabase(db1, "SELECT name FROM groups WHERE id=?", talkId);
String talkName = queryDatabase(db2, "SELECT profile_name FROM contacts WHERE mid=?", talkId);
String name = (groupName != null ? groupName : (talkName != null ? talkName : "No Name" + ":" + "talkId" + talkId));
String media = queryDatabase(db1, "SELECT attachement_type FROM chat_history WHERE server_id=?", serverId);
String mediaDescription = "";
if (media != null) {
switch (media) {
case "7": mediaDescription = moduleContext.getResources().getString(R.string.sticker); break;
case "1": mediaDescription = moduleContext.getResources().getString(R.string.picture); break;
case "2": mediaDescription = moduleContext.getResources().getString(R.string.video); break;
}
}
String from_mid = null, sender_name = null;
if (groupName != null) {
from_mid = queryDatabase(db1, "SELECT from_mid FROM chat_history WHERE server_id=?", serverId);
if (from_mid != null) sender_name = queryDatabase(db2, "SELECT profile_name FROM contacts WHERE mid=?", from_mid);
}
if (sender_name != null) name = groupName + ": " + sender_name;
testWriter.write((timeFormatted != null ? timeFormatted : "No Time: ")
+ name + ": " + content + mediaDescription);
testWriter.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
unresolvedFile.delete();
}
private String formatMessageTime(String timeEpochStr) {
if (timeEpochStr == null) return null;
long timeEpoch = Long.parseLong(timeEpochStr);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
return sdf.format(new Date(timeEpoch));
}
}

View File

@ -3,6 +3,14 @@
<!-- General -->
<string name="positive_button">OK</string>
<string name="negative_button">キャンセル</string>
<string name="ok">OK</string>
<string name="yes">はい</string>
<string name="no">いいえ</string>
<string name="cancel">キャンセル</string>
<string name="sticker">スタンプ</string>
<string name="video">動画</string>
<string name="picture">写真</string>
<string name="reacquisition">再取得</string>
<!-- Xposed API -->
<string name="xposed_desc">LINE をクリーンに。</string>
@ -43,7 +51,28 @@
<string name="modify_response">レスポンスを改変</string>
<string name="button_copy">コピー</string>
<string name="button_paste">ペースト</string>
<string name="call_tone">着信音を鳴らすLSPatch用</string>
<!-- Menu -->
<string name="switch_keep_unread">未読のまま閲覧</string>
<!-- UNSENT CAP -->
<string name="backup">バックアップ</string>
<string name="backup_creation_failed">バックアップの作成に失敗しました</string>
<string name="confirm">確認</string>
<string name="class_not_found">クラスが見つかりません</string>
<string name="confirm_messages">確認済みのメッセージ</string>
<string name="delete_messages">メッセージを削除</string>
<string name="deleted_messages">削除されたメッセージ</string>
<string name="content_moved_to_backup">内容がバックアップファイルに移動されました</string>
<string name="file_content_deleted">ファイルの内容が削除されました</string>
<string name="file_creation_failed">ファイルを作成できませんでした</string>
<string name="file_delete_failed">ファイルの削除に失敗しました</string>
<string name="file_move_failed">ファイルの移動に失敗しました</string>
<string name="file_save_failed">ファイルの保存に失敗しました</string>
<string name="file_not_found">ファイルが見つかりません</string>
<string name="failed_read_backup_file">%s の読み取りに失敗しました</string>
<string name="confirm_delete">本当に削除しますか?</string>
<string name="no_backup_found">何もバックアップされていません</string>
<string name="no_get_restart_app">正しく取得できませんでした。\nアプリを再起動してください</string>
</resources>

View File

@ -1,8 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string translatable="false" name="app_name">LIME</string>
<!-- General -->
<string name="positive_button">OK</string>
<string name="negative_button">Cancel</string>
<string name="ok">OK</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="cancel">Cancel</string>
<string name="sticker">Stickers</string>
<string name="video">Videos</string>
<string name="picture">Photos</string>
<string name="reacquisition">Reacquisition</string>
<!-- Xposed API -->
<string name="xposed_desc">Clean LINE.</string>
@ -43,7 +52,28 @@
<string name="modify_response">Modify responses</string>
<string name="button_copy">Copy</string>
<string name="button_paste">Paste</string>
<string name="call_tone">Notify ringtone of LSPatch</string>
<!-- Menu -->
<string name="switch_keep_unread">Keep unread</string>
<!-- UNSENT CAP -->
<string name="backup">Backup</string>
<string name="backup_creation_failed">Failed to create backup</string>
<string name="confirm">Confirm</string>
<string name="class_not_found">Class not found</string>
<string name="confirm_messages">Confirmed messages</string>
<string name="delete_messages">Deleted messages</string>
<string name="deleted_messages">Deleted messages</string>
<string name="content_moved_to_backup">Content moved to backup file</string>
<string name="file_content_deleted">File contents deleted</string>
<string name="file_creation_failed">Could not create file</string>
<string name="file_delete_failed">Failed to delete file</string>
<string name="file_move_failed">Failed to move file</string>
<string name="file_save_failed">Failed to save file</string>
<string name="file_not_found">File not found</string>
<string name="failed_read_backup_file">Failed to read %s</string>
<string name="confirm_delete">Really want to delete it?</string>
<string name="no_backup_found">Nothing backed up</string>
<string name="no_get_restart_app">Could not get properly.\nPlease restart the app</string>
</resources>