@@ -5459,7 +5459,7 @@ def update_check_times(last_time=None, next_time=None, user=None, increment_coun
54595459 DASHBOARD_DATA['config'] = get_dashboard_config_data()
54605460 update_dashboard()
54615461
5462- if WEB_DASHBOARD_ENABLED:
5462+ if WEB_DASHBOARD_ENABLED or DASHBOARD_ENABLED :
54635463 last_display = get_squeezed_date_from_ts(LAST_CHECK_TIME, show_seconds=DASHBOARD_SHOW_CHECK_SECONDS) if LAST_CHECK_TIME else None
54645464 next_display = get_squeezed_date_from_ts(NEXT_CHECK_TIME, show_seconds=DASHBOARD_SHOW_CHECK_SECONDS) if NEXT_CHECK_TIME else (NEXT_CHECK_DISPLAY or None)
54655465
@@ -6951,7 +6951,7 @@ def fetch_usernames_paginated(bot, get_generator_fn, max_per_batch, total_limit,
69516951
69526952# Monitors activity of the specified Instagram user
69536953def instagram_monitor_user(user, csv_file_name, skip_session, skip_followers, skip_followings, skip_getting_story_details, skip_getting_posts_details, get_more_post_details, wait_for_prev_user=None, signal_loading_complete=None, stop_event=None, user_root_path=None, manual_recheck=False, skip_follow_changes=False): # type: ignore[reportComplexity]
6954- global pbar, DASHBOARD_DATA, VERBOSE_MODE, CHECK_COUNT
6954+ global pbar, DASHBOARD_DATA, VERBOSE_MODE, CHECK_COUNT, NEXT_CHECK_TIME, NEXT_CHECK_DISPLAY
69556955 _thread_local.user = user # Store user in thread-local storage for debug_print
69566956 _thread_local.in_partial_line = False # Track partial line prints
69576957 update_ui_data(targets={user: {'status': 'Starting'}})
@@ -7240,51 +7240,62 @@ def _get_iphone_json(path, params, **kwargs):
72407240 log_activity(f"Error: {error_msg}", user=user)
72417241
72427242 # Handle session recovery for automated checks/challenge errors
7243- if WEB_DASHBOARD_ENABLED and any(t in error_msg for t in FLAGGED_TRIGGERS):
7244- if threading.current_thread() is not threading.main_thread():
7245- update_ui_data(targets={user: {'status': 'Paused: Session re-login required'}})
7246- log_activity("Monitoring paused: Session re-login required via Web Dashboard", user=user)
7247- print(f"* Monitoring paused for {user}. Please refresh/import session via Web Dashboard.")
7248- log_activity(f"Account '{SESSION_USERNAME or '<anonymous>'}' is flagged by Instagram. You must log in and clear any warnings.", user=user)
7249- print(f"* Error: Account '{SESSION_USERNAME or '<anonymous>'}' is flagged by Instagram. You must log in and clear any warnings.")
7243+ if any(t in error_msg for t in FLAGGED_TRIGGERS):
7244+ err_str = f"Session account '{SESSION_USERNAME or '<anonymous>'}' has been flagged. Log into Instagram and clear warnings."
7245+ update_ui_data(targets={user: {'status': f'Paused: {err_str}'}})
7246+ print(f"* Error: {err_str}")
7247+
7248+ # Pause all other threads once the session account is flagged.
7249+ if WEB_DASHBOARD_ENABLED or DASHBOARD_ENABLED:
7250+ for other_user in list(WEB_DASHBOARD_STOP_EVENTS.keys()):
7251+ if other_user != user:
7252+ log_activity(err_str, user=other_user)
7253+ update_check_times(next_time="Paused", user=other_user, increment_count=False)
7254+ stop_monitoring_for_target(other_user)
7255+ update_ui_data(targets={other_user: {'status': f'Paused: {err_str}'}})
7256+ # Update next_check status for this thread
7257+ NEXT_CHECK_TIME = None
7258+ NEXT_CHECK_DISPLAY = "Paused"
7259+ update_check_times(next_time="Paused", user=user, increment_count=False)
7260+ # Pause this thread also
7261+ log_activity("Stopping monitoring", user=user)
72507262 print_cur_ts("\nTimestamp:\t\t\t\t")
72517263 else:
7252- update_ui_data(targets={user: {'status': 'Main Instagram account flagged for automation. Exiting script.'}})
7253- log_activity(f"Account '{SESSION_USERNAME or '<anonymous>'}' is flagged by Instagram for automation. You must log in and clear any warnings.", user=user)
7254- log_activity(f"Exiting script", user=user)
7255- print(f"* Error: Account {SESSION_USERNAME} is flagged by Instagram for automation. You must log in and clear any warnings. Exiting script.")
7256- sys.exit(1)
7264+ print_cur_ts("\nTimestamp:\t\t\t\t")
7265+ signal_handler(signal.SIGINT, None, message='')
72577266
72587267 # Wait for session refresh or stop event
7259- while not (stop_event and stop_event.is_set()):
7260- if SESSION_REFRESHED_EVENT.wait(timeout=1.0):
7261- # Session refreshed! Reload and retry
7262- log_activity("Session/Mode change detected, resuming monitoring...", user=user)
7263- print(f"* Session/Mode change detected for {user}, resuming...")
7264- print_cur_ts("\nTimestamp:\t\t\t\t")
7268+ if WEB_DASHBOARD_ENABLED:
7269+ while not (stop_event and stop_event.is_set()):
7270+ if SESSION_REFRESHED_EVENT.wait(timeout=1.0):
7271+ # Session refreshed! Reload and retry
7272+ log_activity("Session/Mode change detected, resuming monitoring...", user=user)
7273+ print(f"* Session/Mode change detected for {user}, resuming...")
7274+ print_cur_ts("\nTimestamp:\t\t\t\t")
72657275
7266- # Refresh configuration from global settings
7267- skip_session = SKIP_SESSION
7268- skip_followers = SKIP_FOLLOWERS
7269- skip_followings = SKIP_FOLLOWINGS
7270- skip_getting_story_details = SKIP_GETTING_STORY_DETAILS
7271- skip_getting_posts_details = SKIP_GETTING_POSTS_DETAILS
7272- get_more_post_details = GET_MORE_POST_DETAILS
7276+ # Refresh configuration from global settings
7277+ skip_session = SKIP_SESSION
7278+ skip_followers = SKIP_FOLLOWERS
7279+ skip_followings = SKIP_FOLLOWINGS
7280+ skip_getting_story_details = SKIP_GETTING_STORY_DETAILS
7281+ skip_getting_posts_details = SKIP_GETTING_POSTS_DETAILS
7282+ get_more_post_details = GET_MORE_POST_DETAILS
72737283
7274- # Re-run the function from the beginning to reset state with new settings
7275- return instagram_monitor_user(user, csv_file_name, skip_session, skip_followers, skip_followings, skip_getting_story_details, skip_getting_posts_details, get_more_post_details, wait_for_prev_user, signal_loading_complete, stop_event, user_root_path, manual_recheck)
7284+ # Re-run the function from the beginning to reset state with new settings
7285+ return instagram_monitor_user(user, csv_file_name, skip_session, skip_followers, skip_followings, skip_getting_story_details, skip_getting_posts_details, get_more_post_details, wait_for_prev_user, signal_loading_complete, stop_event, user_root_path, manual_recheck)
72767286
7277- if stop_event and stop_event.is_set():
7278- return
7287+ if stop_event and stop_event.is_set():
7288+ return
72797289 else:
72807290 print_cur_ts("\nTimestamp:\t\t\t\t")
72817291
72827292 if WEB_DASHBOARD_ENABLED:
72837293 update_ui_data(targets={user: {'status': 'Error: ' + error_msg}})
7284-
72857294 if threading.current_thread() is threading.main_thread():
7295+ time.sleep(2) # let terminal dashboard fully refresh logs/status in case this generates a script exit
72867296 sys.exit(1)
72877297 else:
7298+ time.sleep(2) # let terminal dashboard fully refresh logs/status in case this generates a script exit
72887299 return
72897300
72907301 story_flag = False
@@ -8316,20 +8327,32 @@ def _get_iphone_json(path, params, **kwargs):
83168327 notification_type="error"
83178328 )
83188329
8319- if WEB_DASHBOARD_ENABLED and any(t in error_msg for t in FLAGGED_TRIGGERS):
8320- if threading.current_thread() is not threading.main_thread():
8321- update_ui_data(targets={user: {'status': 'Paused: Session re-login required'}})
8322- log_activity("Monitoring paused: Session re-login required via Web Dashboard", user=user)
8323- print(f"* Monitoring paused for {user}. Please refresh/import session via Web Dashboard.")
8324- log_activity(f"Account '{SESSION_USERNAME or '<anonymous>'}' is flagged by Instagram. You must log in and clear any warnings.", user=user)
8325- print(f"* Error: Account '{SESSION_USERNAME or '<anonymous>'}' is flagged by Instagram. You must log in and clear any warnings.")
8330+ # Handle session recovery for automated checks/challenge errors
8331+ if any(t in error_msg for t in FLAGGED_TRIGGERS):
8332+ err_str = f"Session account '{SESSION_USERNAME or '<anonymous>'}' has been flagged. Log into Instagram and clear warnings."
8333+ for i in range(50):
8334+ log_activity(f"({i}) - {err_str}", user=user)
8335+ update_ui_data(targets={user: {'status': f'Paused: {err_str}'}})
8336+ print(f"* Error: {err_str}")
8337+
8338+ # Pause all other threads once the session account is flagged.
8339+ if WEB_DASHBOARD_ENABLED or DASHBOARD_ENABLED:
8340+ for other_user in list(WEB_DASHBOARD_STOP_EVENTS.keys()):
8341+ if other_user != user:
8342+ log_activity(err_str, user=other_user)
8343+ update_check_times(next_time="Paused", user=other_user, increment_count=False)
8344+ stop_monitoring_for_target(other_user)
8345+ update_ui_data(targets={other_user: {'status': f'Paused: {err_str}'}})
8346+ # Update next_check status for this thread
8347+ NEXT_CHECK_TIME = None
8348+ NEXT_CHECK_DISPLAY = "Paused"
8349+ update_check_times(next_time="Paused", user=user, increment_count=False)
8350+ # Pause this thread also
8351+ log_activity("Stopping monitoring", user=user)
83268352 print_cur_ts("\nTimestamp:\t\t\t\t")
83278353 else:
8328- update_ui_data(targets={user: {'status': 'Main Instagram account flagged for automation. Exiting script.'}})
8329- log_activity(f"Account '{SESSION_USERNAME or '<anonymous>'}' is flagged by Instagram for automation. You must log in and clear any warnings.", user=user)
8330- log_activity(f"Exiting script", user=user)
8331- print(f"* Error: Account {SESSION_USERNAME} is flagged by Instagram for automation. You must log in and clear any warnings. Exiting script.")
8332- sys.exit(1)
8354+ print_cur_ts("\nTimestamp:\t\t\t\t")
8355+ signal_handler(signal.SIGINT, None, message='')
83338356
83348357 # Wait for session refresh or stop event
83358358 while not (stop_event and stop_event.is_set()):
@@ -10940,6 +10963,9 @@ def _runner(u: str, delay_s: int, idx: int, stop_event: Optional[threading.Event
1094010963 # Still signal completion even on error, so next user can proceed
1094110964 loading_events[idx + 1].set()
1094210965 finally:
10966+ # next code line added per Claude to fix 'deadlock' in multi-threaded mode when an account gets flagged and goes idle
10967+ # reason: loading_events never signaled on early return (note: event.set() is idempotent so calling it twice is harmless)
10968+ loading_events[idx + 1].set()
1094310969 with WEB_DASHBOARD_DATA_LOCK: # type: ignore
1094410970 if u in WEB_DASHBOARD_RECHECK_EVENTS:
1094510971 del WEB_DASHBOARD_RECHECK_EVENTS[u]
@@ -10965,6 +10991,7 @@ def _runner(u: str, delay_s: int, idx: int, stop_event: Optional[threading.Event
1096510991 # but if we're here, we ensure clean exit
1096610992 signal_handler(signal.SIGINT, None)
1096710993
10994+ # this is for main thread to handle the web interface
1096810995 if WEB_DASHBOARD_ENABLED:
1096910996 try:
1097010997 while True:
0 commit comments