Update: 2026-07-06 00:18:03

This commit is contained in:
Hamza-Ayed
2026-07-06 00:18:03 +03:00
parent 27b8a8ec59
commit 03a74fa106
5 changed files with 143 additions and 37 deletions
@@ -91,6 +91,40 @@ object SocialBotClient {
return null
}
fun processOrganicPost(deviceId: String, platform: String, postText: String, targetUrl: String): JSONObject? {
try {
val urlString = "$BASE_URL?action=process_organic_post"
val url = URL(urlString)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "POST"
connection.setRequestProperty("X-Bot-Token", BOT_TOKEN)
val params = "device_id=$deviceId&platform=$platform&post_text=${java.net.URLEncoder.encode(postText, "UTF-8")}&target_url=${java.net.URLEncoder.encode(targetUrl, "UTF-8")}"
connection.doOutput = true
val writer = OutputStreamWriter(connection.outputStream)
writer.write(params)
writer.flush()
writer.close()
val responseCode = connection.responseCode
if (responseCode == 200) {
val scanner = Scanner(connection.inputStream)
val response = if (scanner.hasNext()) scanner.useDelimiter("\\A").next() else ""
scanner.close()
val json = JSONObject(response)
if (json.getString("status") == "success" && !json.isNull("data")) {
return json.getJSONObject("data")
}
}
} catch (e: Exception) {
android.util.Log.e("SocialBotClient", "Exception in processOrganicPost: ${e.message}")
e.printStackTrace()
}
return null
}
fun failTask(taskId: Int, errorMessage: String) {
postData("action=fail_task", "task_id=$taskId&error_message=$errorMessage")
}
@@ -99,54 +99,72 @@ class FacebookBotService : AccessibilityService() {
navigator.openApp()
delay(3000)
val allCollectedTexts = mutableSetOf<String>()
val totalIterations = 20 // 20 iterations * ~15 sec = ~5 minutes of scrolling
val deviceId = android.provider.Settings.Secure.getString(contentResolver, android.provider.Settings.Secure.ANDROID_ID)
val totalIterations = 20
var iterations = 0
var consecutiveNoNewPosts = 0
var lastProcessedPostText = ""
while (iterations < totalIterations) {
Log.d(TAG, "Autonomous Iteration: ${iterations + 1} of $totalIterations")
val initialSize = allCollectedTexts.size
// 1. Expand texts
commentReader.expandPostText()
delay(1000)
// 2. Read feed posts
val posts = commentReader.extractPostsAndComments().map { "[FEED]: $it" }.toMutableList()
val posts = commentReader.extractPostsAndComments()
val currentPost = posts.firstOrNull { it.length > 20 && it != lastProcessedPostText }
// 3. Open comments if available
if (commentReader.openComments()) {
Log.d(TAG, "Opened comments section. Reading...")
delay(4000) // wait for bottom sheet to load
if (currentPost != null) {
Log.d(TAG, "Found valid post: \n$currentPost")
lastProcessedPostText = currentPost
consecutiveNoNewPosts = 0
// 4. Expand long comments
commentReader.expandPostText()
delay(1000)
// 3. Attempt to copy link
val linkCopied = navigator.copyPostLink()
// 5. Read comments
val comments = commentReader.extractPostsAndComments().map { "[COMMENT]: $it" }
posts.addAll(comments)
// 6. Go back to feed
Log.d(TAG, "Going back to main feed...")
navigator.goBack()
delay(3000)
}
// Add to our global collection (Set avoids duplicates)
allCollectedTexts.addAll(posts)
Log.d(TAG, "Collected ${posts.size} texts in this iteration. Total unique so far: ${allCollectedTexts.size}")
if (allCollectedTexts.size == initialSize) {
if (linkCopied) {
// 4. Get copied link from clipboard
val clipboardManager = getSystemService(android.content.Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
val clipboardText = clipboardManager.primaryClip?.getItemAt(0)?.text?.toString() ?: ""
if (clipboardText.contains("http", ignoreCase = true)) {
Log.d(TAG, "Copied Link: $clipboardText")
// 5. Send to Server for organic processing
Log.d(TAG, "Sending to server for organic processing...")
val responseData = SocialBotClient.processOrganicPost(deviceId, "facebook", currentPost, clipboardText)
if (responseData != null && responseData.has("generated_comment")) {
val comment = responseData.getString("generated_comment")
Log.d(TAG, "Server returned comment: $comment")
// 6. Post the comment
if (commentReader.openComments()) {
delay(3000)
val posted = commentPoster.postComment(comment)
if (posted) {
Log.d(TAG, "Successfully posted organic comment!")
SocialBotClient.logMessage(null, "info", "Successfully posted organic comment on: $clipboardText")
}
navigator.goBack() // Close comments
delay(2000)
}
}
} else {
Log.w(TAG, "Copied text was not a URL: $clipboardText")
}
} else {
Log.w(TAG, "Failed to copy link for this post.")
}
} else {
consecutiveNoNewPosts++
Log.d(TAG, "No new posts found in this iteration. (Streak: $consecutiveNoNewPosts)")
if (consecutiveNoNewPosts >= 3) {
Log.d(TAG, "No new posts for 3 consecutive iterations. Reached bottom or stuck. Breaking early.")
Log.d(TAG, "No new posts for 3 consecutive iterations. Breaking early.")
break
}
} else {
consecutiveNoNewPosts = 0
}
Log.d(TAG, "Scrolling down for more posts...")
@@ -155,13 +173,7 @@ class FacebookBotService : AccessibilityService() {
iterations++
}
// Send everything to Gemini AT ONCE to save API costs and generate a comprehensive report
if (allCollectedTexts.isNotEmpty()) {
Log.d(TAG, "Finished scrolling. Sending ${allCollectedTexts.size} total texts to Gemini for one comprehensive report...")
SocialBotClient.evaluatePosts(allCollectedTexts.toList())
}
SocialBotClient.completeTask(task.id, "Autonomous session completed. Scraped ${allCollectedTexts.size} items.")
SocialBotClient.completeTask(task.id, "Autonomous session completed.")
}
"read_posts" -> {
// Logic to read posts and send to backend
@@ -207,4 +207,53 @@ class FacebookNavigator(private val service: AccessibilityService) {
}
return null
}
suspend fun copyPostLink(): Boolean {
val root = service.rootInActiveWindow ?: return false
// 1. Click "Share" (مشاركة)
val shareNodes = mutableListOf<android.view.accessibility.AccessibilityNodeInfo>()
findNodesByText(root, "مشاركة", shareNodes)
findNodesByText(root, "Share", shareNodes)
if (shareNodes.isEmpty()) {
android.util.Log.d("FacebookNavigator", "Share button not found")
return false
}
// Click the first valid Share button
val shareBtn = shareNodes.first()
shareBtn.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK)
kotlinx.coroutines.delay(2000) // Wait for bottom sheet
// 2. Look for "Copy Link" (نسخ الرابط) in the bottom sheet
val newRoot = service.rootInActiveWindow ?: return false
val copyNodes = mutableListOf<android.view.accessibility.AccessibilityNodeInfo>()
findNodesByText(newRoot, "نسخ الرابط", copyNodes)
findNodesByText(newRoot, "Copy link", copyNodes)
if (copyNodes.isEmpty()) {
android.util.Log.d("FacebookNavigator", "Copy Link button not found in sheet")
goBack() // close sheet
return false
}
// Click Copy Link
val copyBtn = copyNodes.first()
copyBtn.performAction(android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK)
kotlinx.coroutines.delay(1000)
return true
}
private fun findNodesByText(node: android.view.accessibility.AccessibilityNodeInfo?, text: String, list: MutableList<android.view.accessibility.AccessibilityNodeInfo>) {
if (node == null) return
val nodeText = (node.text?.toString() ?: "") + " " + (node.contentDescription?.toString() ?: "")
if (nodeText.contains(text, ignoreCase = true)) {
list.add(node)
}
for (i in 0 until node.childCount) {
findNodesByText(node.getChild(i), text, list)
}
}
}