'error', 'message' => 'Unauthorized'])); } $action = $_GET['action'] ?? ''; try { $con = Database::get('main'); switch ($action) { case 'get_task': // The bot asks for a task to do $platform = $_GET['platform'] ?? 'facebook'; $requestedAccountId = $_GET['account_id'] ?? null; $deviceId = $_GET['device_id'] ?? null; // Automatic Plug & Play Device Binding if ($deviceId) { $stmtDev = $con->prepare("SELECT id FROM social_accounts WHERE device_id = ?"); $stmtDev->execute([$deviceId]); $acc = $stmtDev->fetch(PDO::FETCH_ASSOC); if ($acc) { $requestedAccountId = $acc['id']; } else { require_once __DIR__ . '/account_manager.php'; $am = new AccountManager(); // Find an account that doesn't have a device_id yet $stmtFind = $con->prepare("SELECT id FROM social_accounts WHERE platform = ? AND device_id IS NULL AND status = 'active' LIMIT 1"); $stmtFind->execute([$platform]); $newAcc = $stmtFind->fetch(PDO::FETCH_ASSOC); if ($newAcc) { $requestedAccountId = $newAcc['id']; $updateDev = $con->prepare("UPDATE social_accounts SET device_id = ? WHERE id = ?"); $updateDev->execute([$deviceId, $requestedAccountId]); } else { echo json_encode(['status' => 'error', 'message' => 'No available unassigned accounts for this new device']); break; } } } // Find a pending task that is scheduled for now or earlier if ($requestedAccountId) { // If the phone is strictly tied to one account, fetch a task specifically for it // Or fetch an unassigned task and assign it to this phone's account $stmt = $con->prepare(" SELECT id, account_id, type, target_url, prompt_context, generated_comment FROM social_tasks WHERE status = 'pending' AND platform = ? AND (account_id = ? OR account_id IS NULL) AND (scheduled_at IS NULL OR scheduled_at <= NOW()) ORDER BY created_at ASC LIMIT 1 "); $stmt->execute([$platform, $requestedAccountId]); } else { $stmt = $con->prepare(" SELECT id, account_id, type, target_url, prompt_context, generated_comment FROM social_tasks WHERE status = 'pending' AND platform = ? AND (scheduled_at IS NULL OR scheduled_at <= NOW()) ORDER BY created_at ASC LIMIT 1 "); $stmt->execute([$platform]); } $task = $stmt->fetch(PDO::FETCH_ASSOC); if ($task) { require_once __DIR__ . '/account_manager.php'; $am = new AccountManager(); $accountId = $task['account_id'] ?: $requestedAccountId; $account = null; if ($accountId) { // Fetch this specific account details $stmtAcc = $con->prepare(" SELECT id, username, proxy_ip, proxy_port, proxy_username, proxy_password FROM social_accounts WHERE id = ? "); $stmtAcc->execute([$accountId]); $account = $stmtAcc->fetch(PDO::FETCH_ASSOC); if ($account && !$task['account_id']) { $updateTask = $con->prepare("UPDATE social_tasks SET account_id = ? WHERE id = ?"); $updateTask->execute([$accountId, $task['id']]); $task['account_id'] = $accountId; } } else { // Dynamically get an available account and assign it $account = $am->getAvailableAccount($platform, 15); // 15 min cooldown if ($account) { $accountId = $account['id']; $updateTask = $con->prepare("UPDATE social_tasks SET account_id = ? WHERE id = ?"); $updateTask->execute([$accountId, $task['id']]); $task['account_id'] = $accountId; } } if (!$account) { echo json_encode(['status' => 'error', 'message' => 'No active social account available or in cooldown']); break; } if ($account) { $task['bot_username'] = $account['username']; $task['proxy_ip'] = $account['proxy_ip']; $task['proxy_port'] = $account['proxy_port']; $task['proxy_username'] = $account['proxy_username']; $task['proxy_password'] = $account['proxy_password']; } // Mark as in progress and update last active $update = $con->prepare("UPDATE social_tasks SET status = 'in_progress' WHERE id = ?"); $update->execute([$task['id']]); $am->markAccountActive($accountId); // Return task directly in 'data' to preserve compatibility with existing Android bots echo json_encode([ 'status' => 'success', 'data' => $task ]); } else { echo json_encode(['status' => 'success', 'message' => 'No tasks available', 'data' => null]); } case 'process_organic_post': // The bot found a post organically via Accessibility, copied its link, and needs a comment NOW $platform = $_POST['platform'] ?? 'facebook'; $deviceId = $_POST['device_id'] ?? null; $targetUrl = $_POST['target_url'] ?? null; $postText = $_POST['post_text'] ?? ''; if (!$deviceId || !$targetUrl || !$postText) { echo json_encode(['status' => 'error', 'message' => 'device_id, target_url, and post_text are required']); break; } // 0. Duplicate Check (Prevent commenting on the same post twice) $stmtCheck = $con->prepare("SELECT id FROM social_tasks WHERE target_url = ?"); $stmtCheck->execute([$targetUrl]); if ($stmtCheck->fetch()) { echo json_encode(['status' => 'error', 'message' => 'Post already processed by another device']); break; } // 1. Resolve Device ID $stmtDev = $con->prepare("SELECT id FROM social_accounts WHERE device_id = ?"); $stmtDev->execute([$deviceId]); $acc = $stmtDev->fetch(PDO::FETCH_ASSOC); $accountId = $acc ? $acc['id'] : null; if (!$accountId) { // Not registered yet, auto-bind require_once __DIR__ . '/account_manager.php'; $am = new AccountManager(); $stmtFind = $con->prepare("SELECT id FROM social_accounts WHERE platform = ? AND device_id IS NULL AND status = 'active' LIMIT 1"); $stmtFind->execute([$platform]); $newAcc = $stmtFind->fetch(PDO::FETCH_ASSOC); if ($newAcc) { $accountId = $newAcc['id']; $updateDev = $con->prepare("UPDATE social_accounts SET device_id = ? WHERE id = ?"); $updateDev->execute([$deviceId, $accountId]); } else { echo json_encode(['status' => 'error', 'message' => 'No accounts available for new device']); break; } } // 2. Generate Immediate Comment require_once __DIR__ . '/gemini_comment_generator.php'; // Use soft promotion since the app isn't fully launched $generatedComment = generateCommentWithGemini($postText, 'soft_promote_siro'); // 3. Save this initial organic action to database as completed $stmt = $con->prepare(" INSERT INTO social_tasks (account_id, platform, type, target_url, prompt_context, generated_comment, status, completed_at) VALUES (?, ?, 'post_comment', ?, ?, ?, 'completed', NOW()) "); $stmt->execute([$accountId, $platform, $targetUrl, $postText, $generatedComment]); // 4. Schedule Drama (Supporting Accounts) require_once __DIR__ . '/schedule_manager.php'; $sm = new ScheduleManager(); $sm->scheduleDialogueDrama($platform, $targetUrl, $postText, $accountId, 5); // 5 mins delay // 5. Return the generated comment immediately to the Android Bot echo json_encode([ 'status' => 'success', 'data' => [ 'generated_comment' => $generatedComment, 'target_url' => $targetUrl ] ]); break; case 'complete_task': // The bot reports task completion $taskId = $_POST['task_id'] ?? null; $result = $_POST['result'] ?? ''; // e.g. success or error details if ($taskId) { $stmt = $con->prepare("UPDATE social_tasks SET status = 'completed', completed_at = NOW() WHERE id = ?"); $stmt->execute([$taskId]); // Log it $log = $con->prepare("INSERT INTO social_logs (task_id, log_level, message) VALUES (?, 'info', ?)"); $log->execute([$taskId, "Task completed: " . substr($result, 0, 200)]); echo json_encode(['status' => 'success']); } else { echo json_encode(['status' => 'error', 'message' => 'task_id required']); } break; case 'fail_task': // The bot reports task failure $taskId = $_POST['task_id'] ?? null; $errorMsg = $_POST['error_message'] ?? 'Unknown error'; if ($taskId) { $stmt = $con->prepare("UPDATE social_tasks SET status = 'failed', error_message = ? WHERE id = ?"); $stmt->execute([$errorMsg, $taskId]); // Log it $log = $con->prepare("INSERT INTO social_logs (task_id, log_level, message) VALUES (?, 'error', ?)"); $log->execute([$taskId, "Task failed: " . substr($errorMsg, 0, 200)]); echo json_encode(['status' => 'success']); } else { echo json_encode(['status' => 'error', 'message' => 'task_id required']); } break; case 'log': // The bot sends a general log $accountId = $_POST['account_id'] ?? null; $level = $_POST['level'] ?? 'info'; $message = $_POST['message'] ?? ''; $log = $con->prepare("INSERT INTO social_logs (account_id, log_level, message) VALUES (?, ?, ?)"); $log->execute([$accountId, $level, $message]); echo json_encode(['status' => 'success']); break; default: echo json_encode(['status' => 'error', 'message' => 'Invalid action']); } } catch (Exception $e) { http_response_code(500); echo json_encode(['status' => 'error', 'message' => 'Database error: ' . $e->getMessage()]); }