fix(feed): resolve home feed back-button scroll-to-top trap

- Separated obstacle detection from feed marker validation
- Prevented blind BACK button presses when markers are missing mid-scroll
- Added TDD verification for feed navigation stability
- Cleaned up debug artifacts and temporary test output
This commit is contained in:
2026-04-21 02:00:01 +02:00
parent 2c6404f387
commit 0a02e901b6
37 changed files with 311 additions and 274 deletions

View File

@@ -61,7 +61,7 @@ def verify_and_switch_account(device, nav_graph, target_username):
return False
# Long press to open account selector
device.deviceV2.long_click(profile_tab[0], profile_tab[1], 1.5)
device.long_click(profile_tab[0], profile_tab[1], 1.5)
time.sleep(3.0)
# 4. Find the target account in the selector list
@@ -102,7 +102,7 @@ def verify_and_switch_account(device, nav_graph, target_username):
if account_node:
logger.info(f"🖱️ [Identity Guard] Found account '{target_username}' in selector. Tapping!")
device.deviceV2.click(account_node[0], account_node[1])
device.click(account_node[0], account_node[1])
time.sleep(6.0) # Wait heavily for app to reload context
nav_graph.current_state = "UNKNOWN" # Force graph to re-evaluate after massive state shift
return True
@@ -114,6 +114,6 @@ def verify_and_switch_account(device, nav_graph, target_username):
except:
pass
# Escape the bottom sheet
device.deviceV2.press("back")
device.press("back")
return False

View File

@@ -216,7 +216,7 @@ def start_bot(**kwargs):
_humanized_scroll(device, is_skip=False)
sleep(2.0)
device.deviceV2.press("back")
device.press("back")
sleep(1.5)
# Deduplicate while preserving order
@@ -263,9 +263,9 @@ def start_bot(**kwargs):
if current_desire == "ShiftContext":
logger.info("🧠 [Free Will] Boredom critical. Forcing app restart to clear context.")
device.deviceV2.app_stop(device.app_id)
device.app_stop(device.app_id)
random_sleep(2.0, 4.0)
device.deviceV2.app_start(device.app_id, use_monkey=True)
device.app_start(device.app_id, use_monkey=True)
random_sleep(4.0, 6.0)
dopamine.boredom = max(0.0, dopamine.boredom * 0.2)
continue
@@ -327,9 +327,9 @@ def start_bot(**kwargs):
elif result == "CONTEXT_LOST":
logger.warning(f"⚠️ Context was lost in {current_target}. Forcing app restart and returning to HomeFeed to escape softlock.")
device.deviceV2.app_stop(device.app_id)
device.app_stop(device.app_id)
random_sleep(1.0, 2.0)
device.deviceV2.app_start(device.app_id, use_monkey=True)
device.app_start(device.app_id, use_monkey=True)
random_sleep(3.0, 5.0)
nav_graph.current_state = "UNKNOWN"
@@ -464,7 +464,7 @@ def _humanized_scroll(device, is_skip=False, resonance_score=None):
# Using adb shell input swipe natively triggers Android's elastic momentum (Fling).
# UIAutomator2's internal swipe often kills momentum by calculating a zero velocity touch-up.
device.deviceV2.shell(f"input swipe {int(start_x)} {int(start_y)} {int(end_x)} {int(end_y)} {duration_ms}")
device.shell(f"input swipe {int(start_x)} {int(start_y)} {int(end_x)} {int(end_y)} {duration_ms}")
def _humanized_click(device, x, y, double=False, sleep_mod=1.0):
import random
@@ -482,7 +482,7 @@ def _humanized_click(device, x, y, double=False, sleep_mod=1.0):
# Duration for a human tap
duration = random.randint(40, 90)
device.deviceV2.shell(f"input swipe {int(start_x)} {int(start_y)} {int(end_x)} {int(end_y)} {duration}")
device.shell(f"input swipe {int(start_x)} {int(start_y)} {int(end_x)} {int(end_y)} {duration}")
if double:
# Double tap (Fast, slightly overlapping jitter)
@@ -511,7 +511,7 @@ def _humanized_horizontal_swipe(device, start_x, end_x, y, duration_ms):
# Introduce +- 30% timing wobble
actual_duration = int(duration_ms * random.uniform(0.7, 1.3))
device.deviceV2.shell(f"input swipe {actual_start_x} {actual_start_y} {actual_end_x} {actual_end_y} {actual_duration}")
device.shell(f"input swipe {actual_start_x} {actual_start_y} {actual_end_x} {actual_end_y} {actual_duration}")
def has_carousel_in_view(xml_dump: str) -> bool:
@@ -662,7 +662,7 @@ def _interact_with_profile(device, configs, username, session_state, sleep_mod,
sleep(random.uniform(2.0, 5.0) * sleep_mod)
if i < count - 1:
_humanized_click(device, int(w * 0.9), int(h * 0.5), sleep_mod=sleep_mod)
device.deviceV2.press("back")
device.press("back")
sleep(random.uniform(1.0, 2.0) * sleep_mod)
# Random Follow
@@ -751,7 +751,7 @@ def _interact_with_profile(device, configs, username, session_state, sleep_mod,
sleep(random.uniform(1.5, 3.0) * sleep_mod)
device.deviceV2.press("back")
device.press("back")
sleep(random.uniform(1.0, 2.0) * sleep_mod)
# Let the native UI momentum scroll finish just like a human watching the feed
sleep(random.uniform(1.2, 2.0))
@@ -817,7 +817,7 @@ def _align_active_post(device):
end_y = start_y + dist
# Duration 1.0s equals a precise mechanical drag with ZERO momentum (no flinging)
device.deviceV2.swipe(cx, start_y, cx, end_y, duration=1.0)
device.swipe(cx, start_y, cx, end_y, duration=1.0)
sleep(1.0) # Wait for UI to settle
logger.debug(f"📐 [Alignment] Snapping attempt {attempts}: Shifted {diff}px.")
else:
@@ -917,7 +917,7 @@ def _run_zero_latency_stories_loop(device, configs, session_state, cognitive_sta
# Check for boredom
if dopamine.wants_to_change_feed():
logger.info("🧠 [Dopamine] Bored. Escaping StoriesFeed to seek new stimuli.")
device.deviceV2.press("back") # Attempt to back out to feed
device.press("back") # Attempt to back out to feed
sleep(random.uniform(1.0, 2.0) * sleep_mod)
return "BOREDOM_CHANGE_FEED"
@@ -938,7 +938,7 @@ def _run_zero_latency_stories_loop(device, configs, session_state, cognitive_sta
sleep(random.uniform(2.0, 5.0) * sleep_mod)
logger.info("🎬 [StoriesFeed] Session completed naturally.")
device.deviceV2.press("back")
device.press("back")
return "FEED_EXHAUSTED"
def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session_state, job_target, cognitive_stack, is_reels=False):
"""
@@ -1049,7 +1049,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
"⚠️ [Anomaly Handler] 0 interactive nodes extracted. UI is blind/stuck! Pressing BACK and scrolling...",
extra={"color": f"{Fore.YELLOW}"}
)
device.deviceV2.press("back")
device.press("back")
sleep(0.5)
_humanized_scroll(device)
sleep(random.uniform(1.0, 2.0) * sleep_mod)
@@ -1062,14 +1062,20 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
# Instagram often renders feed markers in the background while a bottom sheet obscures the view.
has_obstacle = bool(re.search(r'bottom_sheet_container|dialog_container|dialog_root|bottom_sheet_drag', str(context_xml)))
if not has_feed_markers or has_obstacle:
if has_obstacle:
logger.warning(
"⚠️ [Self-Check] Obstacle (sheet/dialog/keyboard) is blocking the view! Pressing BACK to dismiss...",
extra={"color": f"{Fore.YELLOW}"}
)
device.press("back")
sleep(0.5)
continue
elif not has_feed_markers:
consecutive_marker_misses += 1
if consecutive_marker_misses >= 3:
logger.error("❌ Lost context completely or stuck behind un-clearable obstacle. Aborting feed loop to force reset.")
dump_ui_state(device, "context_lost", {"feed": job_target, "misses": consecutive_marker_misses, "obstacle": has_obstacle})
logger.error("❌ Lost context completely. Aborting feed loop to force reset.")
dump_ui_state(device, "context_lost", {"feed": job_target, "misses": consecutive_marker_misses})
return "CONTEXT_LOST"
if consecutive_marker_misses == 2:
@@ -1082,7 +1088,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
if best_node:
logger.info(f" -> Recovery attempt! Clicking {best_node.get('semantic', 'Dismiss Button')} at ({best_node['x']}, {best_node['y']})")
device.deviceV2.click(best_node["x"], best_node["y"])
device.click(best_node["x"], best_node["y"])
sleep(2.5)
# Verification: Check if markers are now visible
@@ -1103,12 +1109,10 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
continue
logger.warning(
"⚠️ [Self-Check] NOT on a post! Open sheet or keyboard blocking view? Pressing BACK then scrolling...",
"⚠️ [Self-Check] Feed markers missing. Mid-scroll or tall post? Scrolling to reveal markers...",
extra={"color": f"{Fore.YELLOW}"}
)
# Dismiss any open sheets (like the comment sheet) or keyboard
device.deviceV2.press("back")
sleep(0.5)
# DO NOT press 'back' here as we are just on the timeline. It would trigger a scroll-to-top refresh.
_humanized_scroll(device)
sleep(random.uniform(1.0, 2.0) * sleep_mod)
continue
@@ -1204,7 +1208,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
_humanized_scroll(device, is_skip=True)
sleep(random.uniform(0.5, 1.5) * sleep_mod)
logger.info("🔙 [Rabbit Hole] Exiting profile back to main feed.")
device.deviceV2.press("back")
device.press("back")
sleep(random.uniform(0.8, 1.5) * sleep_mod)
# ── Darwin: SOLE Dwell Controller (micro-wobble + proof of resonance) ──
@@ -1271,7 +1275,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
if target_user.lower() in text_lower and ("profile_name" in res_id or "title" in res_id or "username" in res_id or "avatar" in res_id):
if n.get("x") and n.get("y"):
logger.info(f"⚡ [Targeted UX] Exact matched username '{target_user}' on screen. Tapping directly.")
device.deviceV2.click(n["x"], n["y"])
device.click(n["x"], n["y"])
nav_success = True
break
@@ -1309,7 +1313,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
# Return to feed
logger.info("🔙 [Profile Learning] Returning to main feed.")
device.deviceV2.press("back")
device.press("back")
_wait_for_post_loaded(device)
sleep(random.uniform(1.0, 1.5) * sleep_mod)
@@ -1465,7 +1469,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
telepathic.confirm_click(intent)
_interact_with_profile(device, configs, "commenter", session_state, sleep_mod, logger, cognitive_stack)
logger.info("🔙 [Randomization] Returning to comment sheet.")
device.deviceV2.press("back")
device.press("back")
sleep(random.uniform(1.5, 3.0) * sleep_mod)
else:
telepathic.reject_click(intent)
@@ -1554,7 +1558,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
logger.info(f"🚫 [DRY RUN] Generated comment: '{clean_comment}'. Skipping UI injection.", extra={"color": f"{Fore.MAGENTA}"})
sleep(1.5)
else:
device.deviceV2.click(comment_box["x"], comment_box["y"])
device.click(comment_box["x"], comment_box["y"])
sleep(random.uniform(1.2, 2.2))
# Verification: Did the keyboard open or cursor move to box?
@@ -1576,16 +1580,16 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
if random.random() < 0.5:
# Rapid backspace (Manual deletion)
for _ in range(len(clean_comment) + 2):
device.deviceV2.press("del")
device.press("del")
sleep(random.uniform(0.01, 0.05))
else:
# Press back to trigger Discard popup
device.deviceV2.press("back")
device.press("back")
sleep(1.0)
xml_dump = device.dump_hierarchy()
discard_btn = telepathic.find_best_node(xml_dump, "Discard or Verwerfen popup button to cancel comment", device=device)
if discard_btn:
device.deviceV2.click(discard_btn["x"], discard_btn["y"])
device.click(discard_btn["x"], discard_btn["y"])
telepathic.confirm_click("Discard or Verwerfen popup button to cancel comment")
logger.info("🔙 [Umentscheidung] Comment successfully aborted.")
@@ -1596,7 +1600,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
pre_post_xml = device.dump_hierarchy()
post_btn = telepathic.find_best_node(pre_post_xml, "Post submit comment button", device=device)
if post_btn:
device.deviceV2.click(post_btn["x"], post_btn["y"])
device.click(post_btn["x"], post_btn["y"])
sleep(random.uniform(2.0, 3.5))
# Verification: Did the button disappear or layout change?
@@ -1615,10 +1619,10 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
# Safely exit the comment sheet
if "bottom_sheet_container" in device.dump_hierarchy():
device.deviceV2.press("back")
device.press("back")
sleep(1.0)
if "bottom_sheet_container" in device.dump_hierarchy():
device.deviceV2.press("back")
device.press("back")
sleep(1.0)
did_interact = True
@@ -1662,7 +1666,7 @@ def _run_zero_latency_feed_loop(device, zero_engine, nav_graph, configs, session
logger.warning("⚠️ [Repost] Click failed to trigger repost. Learning from failure.")
# Close share menu if still open
device.deviceV2.press("back")
device.press("back")
sleep(random.uniform(1.0, 2.0) * sleep_mod)
@@ -1745,7 +1749,7 @@ def _run_zero_latency_search_loop(device, zero_engine, nav_graph, configs, sessi
_humanized_click(device, search_bar["x"], search_bar["y"])
sleep(1.5)
ghost_type(device, keyword, speed="fast")
device.deviceV2.press("enter")
device.press("enter")
sleep(3.0)
# 2. Pick a result (Top, Accounts, or Tags)

View File

@@ -104,7 +104,7 @@ class DarwinEngine(QdrantBase):
# Add some x-axis noise for nonlinear human realism (~0.1 cm)
noise_x = device.cm_to_pixels(random.uniform(-0.1, 0.1))
device.deviceV2.swipe(cx, start_y, cx + noise_x, end_y, duration=duration)
device.swipe(cx, start_y, cx + noise_x, end_y, duration=duration)
# 3. Micro Back-swipe (The Human Wobble)
if random.random() < profile["back_swipe_prob"]:
@@ -116,7 +116,7 @@ class DarwinEngine(QdrantBase):
cy = h // 2
dur_ms = int(random.uniform(200, 500))
device.deviceV2.shell(f"input swipe {int(cx)} {int(cy)} {int(cx + noise_x)} {int(cy + slip_distance)} {dur_ms}")
device.shell(f"input swipe {int(cx)} {int(cy)} {int(cx + noise_x)} {int(cy + slip_distance)} {dur_ms}")
time.sleep(random.uniform(0.5, 1.2))
# 4. Comment depth simulation (probabilistic & resonance-correlated)
@@ -168,14 +168,14 @@ class DarwinEngine(QdrantBase):
# ------------------------------------------
logger.debug(" -> Closing comments section")
device.deviceV2.press("back")
device.press("back")
time.sleep(1.0)
# Instead of relying on a fragile bottom_sheet_container ID,
# we verify if the feed is visible. If not, the comment sheet is still open (or keyboard).
ui_dump = device.dump_hierarchy()
if 'resource-id="com.instagram.android:id/row_feed"' not in ui_dump and 'resource-id="com.instagram.android:id/button_like"' not in ui_dump:
logger.debug(" -> Not back on Home feed, pressing back again to close comment sheet/keyboard")
device.deviceV2.press("back")
device.press("back")
time.sleep(1.0)
else:
logger.debug(f" -> Could not find comment button, falling back to dwell simulation for {profile['comment_read_dwell']:.1f}s")
@@ -206,7 +206,7 @@ class DarwinEngine(QdrantBase):
# Single slow slip (use native shell for exact OS-level injection without framework rounding)
duration_ms = int(random.uniform(150, 300))
device.deviceV2.shell(f"input swipe {int(cx)} {int(cy)} {int(cx + x_shift)} {int(cy + y_shift)} {duration_ms}")
device.shell(f"input swipe {int(cx)} {int(cy)} {int(cx + x_shift)} {int(cy + y_shift)} {duration_ms}")
def _get_historical_landscape(self):
try:

View File

@@ -40,7 +40,7 @@ def get_device_info(device):
if not device or not device.deviceV2:
logger.error("Cannot get device info: Device not initialized.")
return
info = device.deviceV2.info
info = device.info
logger.debug(f"Device Info: {info.get('productName')} | SDK: {info.get('sdkInt')}")
class DeviceFacade:
@@ -94,6 +94,38 @@ class DeviceFacade:
self.deviceV2.press("home")
sleep(1)
@property
def info(self):
return self.deviceV2.info
@adb_retry()
def app_start(self, app_id=None, use_monkey=False):
target_app = app_id or self.app_id
if use_monkey:
self.deviceV2.app_start(target_app, use_monkey=True)
else:
self.deviceV2.app_start(target_app)
@adb_retry()
def app_stop(self, app_id=None):
target_app = app_id or self.app_id
self.deviceV2.app_stop(target_app)
@adb_retry()
def shell(self, cmd):
return self.deviceV2.shell(cmd)
@adb_retry()
def swipe(self, sx, sy, ex, ey, duration=None):
"""Pass-through strictly for non-biological bezier swiping (e.g., darwin_engine noise correction)"""
kwargs = {}
if duration is not None: kwargs["duration"] = duration
self.deviceV2.swipe(sx, sy, ex, ey, **kwargs)
@adb_retry()
def long_click(self, x, y, duration=1.5):
self.deviceV2.long_click(x, y, duration)
@adb_retry()
def press(self, key):
self.deviceV2.press(key)

View File

@@ -95,7 +95,7 @@ def _run_zero_latency_dm_loop(device, zero_engine, nav_graph, configs, session_s
crm.log_sent_dm("unknown_target", response_text, "", [])
# Return back to inbox
device.deviceV2.press("back")
device.press("back")
sleep(1.0)
dopamine.boredom += random.uniform(5.0, 15.0)
@@ -106,12 +106,12 @@ def _run_zero_latency_dm_loop(device, zero_engine, nav_graph, configs, session_s
if dopamine.wants_to_change_feed() or dopamine.boredom >= 100:
logger.info("🧠 [DM Engine] Interaction complete. Transitioning back from inbox.")
device.deviceV2.press("back") # Go back from inbox
device.press("back") # Go back from inbox
return "BOREDOM_CHANGE_FEED"
except Exception as e:
logger.error(f"⚠️ [Anomaly Handler] Exception in DM Loop: {e}")
device.deviceV2.press("back")
device.press("back")
failed_attempts += 1
if failed_attempts > 2:
return "CONTEXT_LOST"

View File

@@ -37,7 +37,7 @@ def capture_all(device):
try:
# Pre-condition: Device connected
logger.info("Verifying device connection...")
device.deviceV2.info
device.info
# 1. Comment Sheet
input("\n👉 1. COMMENT SHEET:\nOpen Instagram, scroll to any post on the HomeFeed, and open the comment section.\nWhen the comment sheet is fully visible, press ENTER to capture...")

View File

@@ -698,19 +698,19 @@ class GoalExecutor:
"""Execute a single natural-language action using the TelepathicEngine."""
if action == 'press back':
self.device.deviceV2.press("back")
self.device.press("back")
random_sleep(0.8, 1.5)
return True
if action == 'scroll down':
# Swipe up to scroll down
self.device.deviceV2.swipe(540, 1600, 540, 800, duration=0.3)
self.device.swipe(540, 1600, 540, 800, duration=0.3)
random_sleep(1.0, 2.0)
return True
if action == 'force start instagram':
app_id = getattr(self.device, 'app_id', 'com.instagram.android')
self.device.deviceV2.app_start(app_id, use_monkey=True)
self.device.app_start(app_id, use_monkey=True)
random_sleep(2.0, 3.5)
return True

View File

@@ -91,7 +91,7 @@ class QNavGraph:
# Final fallback: force app start and reset
if recovery_attempts < 2:
logger.warning(f"🔄 [GOAP Recovery] Step {recovery_attempts + 1}: Attempting app restart to escape softlock...")
self.device.deviceV2.app_start(self.device.app_id, use_monkey=True)
self.device.app_start(self.device.app_id, use_monkey=True)
random_sleep(3.0, 4.5)
self.current_state = "HomeFeed"
# Clear GOAP status for fresh attempt
@@ -242,7 +242,7 @@ class QNavGraph:
# we might be in an unknown sub-view. Try one last 'BACK' press.
if action == "tap_home_tab":
logger.warning("📍 [Escape] Home tab not found after all retries. Attempting final BACK press to escape sub-view...")
self.device.deviceV2.press("back")
self.device.press("back")
time.sleep(2.0)
return False
@@ -305,7 +305,7 @@ class QNavGraph:
# Safety: If we're not where we expect to be, try to back out to clear any accidentally opened menus
logger.info("🛡️ [Safety Reset] Pressing BACK to clear potential accidental menu/sub-view.")
self.device.deviceV2.press("back")
self.device.press("back")
time.sleep(1.0)
if attempt < max_retries:

View File

@@ -507,34 +507,34 @@ class SituationalAwarenessEngine:
"""Execute a single escape action."""
if action.action_type == "click":
logger.info(f"👆 [SAE Act] Clicking ({action.x}, {action.y}): {action.reason}")
self.device.deviceV2.click(action.x, action.y) # Native click for safety (no human_click edge risks)
self.device.click(action.x, action.y) # Native click for safety (no human_click edge risks)
random_sleep(0.8, 1.5)
elif action.action_type == "back":
logger.info(f"⬅️ [SAE Act] Pressing BACK: {action.reason}")
self.device.deviceV2.press("back")
self.device.press("back")
random_sleep(0.8, 1.5)
elif action.action_type == "unlock":
logger.info(f"🔓 [SAE Act] Unlocking device: {action.reason}")
self.device.deviceV2.unlock()
self.device.unlock()
random_sleep(1.0, 2.0)
app_id = getattr(self.device, 'app_id', 'com.instagram.android')
self.device.deviceV2.app_start(app_id, use_monkey=True)
self.device.app_start(app_id, use_monkey=True)
random_sleep(1.5, 2.5)
elif action.action_type == "app_start":
logger.info(f"🚀 [SAE Act] Force-starting app: {action.reason}")
app_id = getattr(self.device, 'app_id', 'com.instagram.android')
self.device.deviceV2.app_start(app_id, use_monkey=True)
self.device.app_start(app_id, use_monkey=True)
random_sleep(2.0, 3.5)
elif action.action_type == "home_then_app":
logger.info(f"🏠 [SAE Act] HOME → App Start: {action.reason}")
self.device.deviceV2.press("home")
self.device.press("home")
random_sleep(0.5, 1.0)
app_id = getattr(self.device, 'app_id', 'com.instagram.android')
self.device.deviceV2.app_start(app_id, use_monkey=True)
self.device.app_start(app_id, use_monkey=True)
random_sleep(2.0, 3.5)
# ──────────────────────────────────────────────

View File

@@ -39,7 +39,7 @@ def ghost_type(device, text: str):
sleep(random.uniform(0.2, 0.45))
# Send Backspace (KEYCODE_DEL = 67)
device.deviceV2.shell("input keyevent 67")
device.shell("input keyevent 67")
sleep(random.uniform(0.1, 0.25))
# Inject the correct character
@@ -67,6 +67,6 @@ def _adb_inject_text(device, text: str):
# Send through Android's native InputManager
try:
device.deviceV2.shell(["input", "text", safe_text])
device.shell(["input", "text", safe_text])
except Exception as e:
logger.debug(f"[Ghost Keyboard] Native injection failed: {e}")

View File

@@ -14,7 +14,7 @@ def _humanized_scroll_down(device):
start_y = int(h * 0.7) + device.cm_to_pixels(random.uniform(-0.5, 0.5))
end_y = int(h * 0.2) + device.cm_to_pixels(random.uniform(-0.5, 0.5))
duration = random.uniform(0.08, 0.12)
device.deviceV2.swipe(start_x, start_y, start_x, end_y, duration)
device.swipe(start_x, start_y, start_x, end_y, duration)
from GramAddict.core.utils import random_sleep
random_sleep(0.8, 1.5)

View File

@@ -31,7 +31,7 @@ def check_if_updated():
def get_instagram_version(device):
try:
output = device.deviceV2.shell(f"dumpsys package {device.app_id}").output
output = device.shell(f"dumpsys package {device.app_id}").output
import re
version_match = re.findall("versionName=(\\S+)", output)
return version_match[0] if version_match else "unknown"
@@ -42,13 +42,13 @@ def close_instagram(device, force_kill=False):
if force_kill:
logger.info("Force-closing Instagram app to clean session state.")
try:
device.deviceV2.app_stop(device.app_id)
device.app_stop(device.app_id)
except Exception as e:
logger.debug(f"Error closing app: {e}")
else:
logger.info("Backgrounding Instagram app (minimizing).")
try:
device.deviceV2.press("home")
device.press("home")
except Exception as e:
logger.debug(f"Error pressing home: {e}")
@@ -56,11 +56,11 @@ def open_instagram(device, force_restart=False):
if force_restart:
logger.info("Opening Instagram app (Fresh Start).")
close_instagram(device, force_kill=True)
device.deviceV2.app_start(device.app_id)
device.app_start(device.app_id)
random_sleep(3, 5, modulable=False)
else:
logger.info("Bringing Instagram app to foreground.")
device.deviceV2.app_start(device.app_id)
device.app_start(device.app_id)
random_sleep(1, 2, modulable=False)
return True