import logging import uiautomator2 as u2 import time import os class FacebookBot: def __init__(self, device_ip: str): logging.info(f"Đang kết nối tới thiết bị {device_ip} để chạy Facebook...") self.d = u2.connect(device_ip) logging.info("Kết nối thành công!") def push_image_to_gallery(self, local_image_path: str): if not local_image_path or not os.path.exists(local_image_path): logging.warning("Không có file ảnh cục bộ để đẩy lên điện thoại.") return False logging.info(f"Đang đẩy ảnh {local_image_path} vào điện thoại...") # Đẩy ảnh vào thư mục Pictures remote_path = "/sdcard/Pictures/n8n_fb_comment.jpg" self.d.push(local_image_path, remote_path) # Gọi Media Scanner để Thư viện ảnh nhận diện ngay lập tức logging.info("Đang cập nhật thư viện ảnh...") self.d.shell(f'am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://{remote_path}') time.sleep(2) return True def post_comment(self, group_id: str, content: str, local_image_path: str = None) -> dict: try: self.d.screen_on() # Đẩy ảnh vào điện thoại nếu có has_image = False if local_image_path: has_image = self.push_image_to_gallery(local_image_path) logging.info(f"Khởi động Facebook và vào Group ID: {group_id}...") # Dùng lệnh ADB shell để mở thẳng Deep Link của Group self.d.shell(f'am start -a android.intent.action.VIEW -d "fb://group/{group_id}"') time.sleep(8) # Đợi load giao diện group self.dump_ui_for_debug("fb_step1_open_group.xml") # Kiểm tra xem Group có bị lỗi "Không hiển thị" (Do sai ID, group chết, group kín) hay không err_msg1 = self.d(descriptionContains="Nội dung này không hiển thị") err_msg2 = self.d(descriptionContains="chỉ hiển thị với một số người") if err_msg1.exists or err_msg2.exists: logging.warning(f"Group {group_id} không tồn tại hoặc bạn không có quyền truy cập.") return {"status": "error", "message": "Group không tồn tại hoặc không có quyền truy cập."} # Quét nút Bình luận, nếu không thấy thì vuốt xuống (vì ảnh bìa group che mất) logging.info("Tìm nút Bình luận của bài viết đầu tiên...") comment_btn = None for _ in range(7): # Thử vuốt tối đa 7 lần # Thử quét bằng Regex (Không phân biệt hoa thường) ở cả description và text c_desc_vn = self.d(descriptionMatches="(?i).*bình luận.*") c_text_vn = self.d(textMatches="(?i).*bình luận.*") c_desc_en = self.d(descriptionMatches="(?i).*comment.*") c_text_en = self.d(textMatches="(?i).*comment.*") if c_desc_vn.exists: comment_btn = c_desc_vn; break if c_text_vn.exists: comment_btn = c_text_vn; break if c_desc_en.exists: comment_btn = c_desc_en; break if c_text_en.exists: comment_btn = c_text_en; break # Vuốt lên một chút self.d.swipe_ext("up", scale=0.5) time.sleep(1.5) self.dump_ui_for_debug("fb_step2_scrolling.xml") if comment_btn and comment_btn.exists: comment_btn[0].click() # Click vào bài đầu tiên tìm thấy self.dump_ui_for_debug("fb_step3_clicked_comment.xml") else: self.dump_ui_for_debug("error_fb_no_comment_btn.xml") return {"status": "error", "message": "Không tìm thấy nút Bình luận. Đã lưu dump UI."} time.sleep(4) # Tìm ô nhập liệu "Viết bình luận công khai..." logging.info("Nhập nội dung text...") # Facebook có thể dùng EditText hoặc một class khác tùy phiên bản edit_box = self.d(className="android.widget.EditText") if not edit_box.exists: # Fallback: Tìm ô chứa chữ "Viết bình luận" hoặc "Write a comment" edit_box = self.d(descriptionMatches="(?i).*viết bình luận.*") if not edit_box.exists: edit_box = self.d(textMatches="(?i).*viết bình luận.*") if edit_box.exists: edit_box.click() time.sleep(1) edit_box.set_text(content) self.dump_ui_for_debug("fb_step7_text_entered.xml") else: self.dump_ui_for_debug("error_fb_no_edit_box.xml") return {"status": "error", "message": "Không tìm thấy ô gõ chữ. Có thể bạn bị cấm comment ở Group này."} # Chọn ảnh nếu có if has_image: logging.info("Đang chọn ảnh đính kèm...") # Nút chọn ảnh thường có chữ Camera hoặc Ảnh/Video photo_btn = self.d(descriptionContains="ảnh") if not photo_btn.exists: photo_btn = self.d(descriptionContains="photo") if photo_btn.exists: photo_btn.click() time.sleep(3) self.dump_ui_for_debug("fb_step5_camera_opened.xml") # Chọn ảnh đầu tiên trong thư viện (vừa mới push vào) # Facebook gallery thường có checkbox hoặc chỉ cần click vào vùng ảnh gallery_images = self.d(className="android.widget.ImageView") if gallery_images.count >= 2: gallery_images[1].click() # Bỏ qua icon đầu tiên thường là icon camera time.sleep(1) self.dump_ui_for_debug("fb_step6_image_selected.xml") # Nút Xong / Done done_btn = self.d(textContains="Xong") if not done_btn.exists: done_btn = self.d(textContains="Done") if done_btn.exists: done_btn.click() time.sleep(1) else: logging.warning("Không tìm thấy nút đính kèm ảnh, sẽ chỉ gửi text.") # Bấm gửi logging.info("Bấm nút Gửi (Send)...") send_btn = self.d(descriptionContains="Gửi") if not send_btn.exists: send_btn = self.d(descriptionContains="Send") if send_btn.exists: send_btn.click() time.sleep(3) return {"status": "success", "message": "Đã comment thành công!"} else: self.dump_ui_for_debug("error_fb_no_send_btn.xml") return {"status": "error", "message": "Không tìm thấy nút Gửi."} except Exception as e: logging.error(f"Lỗi Facebook Bot: {str(e)}") return {"status": "error", "message": f"Lỗi không xác định: {str(e)}"} finally: logging.info("Thoát ra màn hình chính (Homescreen)...") self.d.press("home") def dump_ui_for_debug(self, filename: str): xml_dump = self.d.dump_hierarchy() with open(filename, "w", encoding="utf-8") as f: f.write(xml_dump) logging.error(f"Đã lưu giao diện lỗi vào file {filename}")