Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -69,7 +69,8 @@ CACHE_UPDATE_INTERVAL_SECONDS = int(os.getenv('CACHE_UPDATE_INTERVAL_SECONDS', 6
|
|
| 69 |
# Webhook URLs
|
| 70 |
SCAMMER_WEBHOOK_URL = os.getenv("SCAMMER_WEBHOOK_URL")
|
| 71 |
VALUE_WEBHOOK_URL = os.getenv("VALUE_WEBHOOK_URL")
|
| 72 |
-
|
|
|
|
| 73 |
|
| 74 |
|
| 75 |
# --- Global Cache ---
|
|
@@ -79,7 +80,7 @@ cache = {
|
|
| 79 |
"user_scammers": [],
|
| 80 |
"server_scammers": [],
|
| 81 |
"dwc": [],
|
| 82 |
-
"trusted": [], #
|
| 83 |
"dupes": [], # List of duped usernames
|
| 84 |
"last_updated": None, # Timestamp of the last successful/partial update
|
| 85 |
"is_ready": False, # Is the cache populated at least once?
|
|
@@ -378,29 +379,33 @@ def process_dwc_data(values): # For DWC Sheet
|
|
| 378 |
processed_data.append(processed_item)
|
| 379 |
return processed_data
|
| 380 |
|
| 381 |
-
def process_trusted_data(values): #
|
| 382 |
if not values: return []
|
| 383 |
processed_data = []
|
| 384 |
for row in values: # Expected range like B6:E
|
| 385 |
-
if not row or len(row) <
|
| 386 |
# Indices based on B6:E (0-indexed from B)
|
| 387 |
-
|
| 388 |
-
discord_username = clean_string_optional(row[1]) if len(row) > 1 else None # Col C
|
| 389 |
discord_server_id = clean_string_optional(row[2]) if len(row) > 2 else None # Col D
|
| 390 |
roblox_username = clean_string_optional(row[3]) if len(row) > 3 else None # Col E
|
| 391 |
-
|
| 392 |
-
# Skip if all identifiers are missing
|
| 393 |
-
if not
|
| 394 |
-
|
| 395 |
-
if
|
|
|
|
|
|
|
|
|
|
| 396 |
continue
|
| 397 |
-
|
| 398 |
processed_item = {
|
| 399 |
-
'
|
| 400 |
-
'
|
| 401 |
'discord_server_id': discord_server_id,
|
| 402 |
'roblox_username': roblox_username,
|
| 403 |
-
'roblox_avatar_url': None # Will be filled later
|
|
|
|
| 404 |
}
|
| 405 |
processed_data.append(processed_item)
|
| 406 |
return processed_data
|
|
@@ -532,8 +537,8 @@ async def update_cache_periodically():
|
|
| 532 |
"user_scammers": [],
|
| 533 |
"server_scammers": [],
|
| 534 |
"dwc": [],
|
|
|
|
| 535 |
"dupes": [],
|
| 536 |
-
"trusted": [], # List of trusted users/servers
|
| 537 |
}
|
| 538 |
current_errors = {} # Track errors for specific fetches/sheets
|
| 539 |
|
|
@@ -543,19 +548,19 @@ async def update_cache_periodically():
|
|
| 543 |
f"{quote_sheet_name(USER_SCAMMER_SHEET)}!{USER_SCAMMER_RANGE}",
|
| 544 |
f"{quote_sheet_name(SERVER_SCAMMER_SHEET)}!{SERVER_SCAMMER_RANGE}",
|
| 545 |
f"{quote_sheet_name(DWC_SHEET)}!{DWC_RANGE}",
|
| 546 |
-
f"{quote_sheet_name(TRUSTED_SHEET)}!{TRUSTED_RANGE}",
|
| 547 |
]
|
| 548 |
scammer_dwc_processor_map = {
|
| 549 |
USER_SCAMMER_SHEET: process_user_scammer_data,
|
| 550 |
SERVER_SCAMMER_SHEET: process_server_scammer_data,
|
| 551 |
DWC_SHEET: process_dwc_data,
|
| 552 |
-
TRUSTED_SHEET: process_trusted_data,
|
| 553 |
}
|
| 554 |
scammer_dwc_target_key_map = {
|
| 555 |
USER_SCAMMER_SHEET: "user_scammers",
|
| 556 |
SERVER_SCAMMER_SHEET: "server_scammers",
|
| 557 |
DWC_SHEET: "dwc",
|
| 558 |
-
TRUSTED_SHEET: "trusted",
|
| 559 |
}
|
| 560 |
|
| 561 |
values_dupes_ranges = [f"{quote_sheet_name(DUPE_LIST_SHEET)}!{DUPE_LIST_RANGE}"]
|
|
@@ -657,10 +662,11 @@ async def update_cache_periodically():
|
|
| 657 |
# --- Fetch Roblox Avatars (for new data before comparison/webhook) ---
|
| 658 |
if not current_errors.get("scammer_dwc_batch") and \
|
| 659 |
not current_errors.get("process_user_scammers") and \
|
| 660 |
-
not current_errors.get("process_dwc")
|
|
|
|
| 661 |
logger.info("Fetching Roblox avatars for newly processed data...")
|
| 662 |
avatar_tasks = []
|
| 663 |
-
entries_needing_avatars = new_cache_data.get("user_scammers", []) + new_cache_data.get("dwc", []) + new_cache_data.get("trusted", [])
|
| 664 |
for entry in entries_needing_avatars:
|
| 665 |
if entry.get('roblox_username'):
|
| 666 |
avatar_tasks.append(fetch_avatar_for_entry_update(session, entry))
|
|
@@ -668,7 +674,7 @@ async def update_cache_periodically():
|
|
| 668 |
await asyncio.gather(*avatar_tasks) # Exceptions logged within helper
|
| 669 |
logger.info(f"Finished fetching avatars for {len(avatar_tasks)} potential new entries.")
|
| 670 |
else:
|
| 671 |
-
logger.warning("Skipping avatar fetching due to errors in fetching/processing scammer/dwc data.")
|
| 672 |
|
| 673 |
|
| 674 |
# --- Change Detection & Webhook Preparation (ONLY if cache is ready) ---
|
|
@@ -892,27 +898,17 @@ async def update_cache_periodically():
|
|
| 892 |
|
| 893 |
# Update scammer/DWC sections if their batch succeeded AND processing succeeded
|
| 894 |
if "scammer_dwc_batch" not in current_errors:
|
| 895 |
-
for key in ["user_scammers", "server_scammers", "dwc"
|
| 896 |
process_error_key = f"process_{key}"
|
| 897 |
-
logger.info(f"Partial update check for key: '{key}'")
|
| 898 |
if process_error_key not in current_errors:
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
old_data = cache.get(key)
|
| 902 |
-
new_data = new_cache_data.get(key) # Use .get for safety
|
| 903 |
-
logger.info(f"--> Comparing for '{key}': cache has {len(old_data) if old_data is not None else 'None'} items, new data has {len(new_data) if new_data is not None else 'None'} items.")
|
| 904 |
-
|
| 905 |
-
if old_data != new_data:
|
| 906 |
-
logger.info(f"--> Data differs for '{key}'. UPDATING CACHE.")
|
| 907 |
-
cache[key] = new_data
|
| 908 |
partial_update_details.append(key)
|
| 909 |
update_occurred = True
|
| 910 |
-
else:
|
| 911 |
-
logger.info(f"--> Data is identical for '{key}'. Skipping update.")
|
| 912 |
else:
|
| 913 |
-
logger.warning(f"
|
| 914 |
else:
|
| 915 |
-
logger.warning("Skipping update for 'user_scammers', 'server_scammers', 'dwc'
|
| 916 |
|
| 917 |
if update_occurred:
|
| 918 |
cache["last_updated"] = current_time # Mark partial update time
|
|
@@ -1012,8 +1008,8 @@ async def get_status():
|
|
| 1012 |
"user_scammers": len(cache.get("user_scammers", [])),
|
| 1013 |
"server_scammers": len(cache.get("server_scammers", [])),
|
| 1014 |
"dwc_entries": len(cache.get("dwc", [])),
|
|
|
|
| 1015 |
"duped_usernames": len(cache.get("dupes", [])),
|
| 1016 |
-
"trusted_entries": len(cache.get("trusted", [])),
|
| 1017 |
},
|
| 1018 |
"value_change_categories_in_last_cycle": len(cache.get("value_changes", {}))
|
| 1019 |
}
|
|
@@ -1063,13 +1059,13 @@ async def get_all_value_changes():
|
|
| 1063 |
|
| 1064 |
@app.get("/api/scammers")
|
| 1065 |
async def get_scammers():
|
| 1066 |
-
"""Get all scammer and
|
| 1067 |
check_cache_readiness()
|
| 1068 |
return {
|
| 1069 |
"users": cache.get("user_scammers", []),
|
| 1070 |
"servers": cache.get("server_scammers", []),
|
| 1071 |
"dwc": cache.get("dwc", []),
|
| 1072 |
-
"trusted": cache.get("trusted", [])
|
| 1073 |
}
|
| 1074 |
|
| 1075 |
@app.get("/api/dupes")
|
|
|
|
| 69 |
# Webhook URLs
|
| 70 |
SCAMMER_WEBHOOK_URL = os.getenv("SCAMMER_WEBHOOK_URL")
|
| 71 |
VALUE_WEBHOOK_URL = os.getenv("VALUE_WEBHOOK_URL")
|
| 72 |
+
# Optional: Separate webhook for dupe checks? Keep using the general one for now.
|
| 73 |
+
DUPE_CHECK_WEBHOOK_URL = os.getenv("WEBHOOK_URL")
|
| 74 |
|
| 75 |
|
| 76 |
# --- Global Cache ---
|
|
|
|
| 80 |
"user_scammers": [],
|
| 81 |
"server_scammers": [],
|
| 82 |
"dwc": [],
|
| 83 |
+
"trusted": [], # New cache key for trusted entries
|
| 84 |
"dupes": [], # List of duped usernames
|
| 85 |
"last_updated": None, # Timestamp of the last successful/partial update
|
| 86 |
"is_ready": False, # Is the cache populated at least once?
|
|
|
|
| 379 |
processed_data.append(processed_item)
|
| 380 |
return processed_data
|
| 381 |
|
| 382 |
+
def process_trusted_data(values): # New function for Trusted Sheet
|
| 383 |
if not values: return []
|
| 384 |
processed_data = []
|
| 385 |
for row in values: # Expected range like B6:E
|
| 386 |
+
if not row or len(row) < 1: continue # Need at least one identifier
|
| 387 |
# Indices based on B6:E (0-indexed from B)
|
| 388 |
+
discord_user_id = clean_string_optional(row[0]) if len(row) > 0 else None # Col B
|
| 389 |
+
# discord_username = clean_string_optional(row[1]) if len(row) > 1 else None # Col C - Not currently used for matching, but keep for potential future use
|
| 390 |
discord_server_id = clean_string_optional(row[2]) if len(row) > 2 else None # Col D
|
| 391 |
roblox_username = clean_string_optional(row[3]) if len(row) > 3 else None # Col E
|
| 392 |
+
|
| 393 |
+
# Skip if all relevant identifiers are missing
|
| 394 |
+
if not discord_user_id and not discord_server_id and not roblox_username: continue
|
| 395 |
+
|
| 396 |
+
# Skip if it looks like a header row (check common header names)
|
| 397 |
+
if (str(discord_user_id).lower() == 'discord user id' or
|
| 398 |
+
str(discord_server_id).lower() == 'discord server id' or
|
| 399 |
+
str(roblox_username).lower() == 'roblox username'):
|
| 400 |
continue
|
| 401 |
+
|
| 402 |
processed_item = {
|
| 403 |
+
'status': 'Trusted', # Add a status field
|
| 404 |
+
'discord_user_id': discord_user_id,
|
| 405 |
'discord_server_id': discord_server_id,
|
| 406 |
'roblox_username': roblox_username,
|
| 407 |
+
'roblox_avatar_url': None # Will be filled later if roblox_username exists
|
| 408 |
+
# Note: No explanation or evidence expected for trusted entries based on B6:E
|
| 409 |
}
|
| 410 |
processed_data.append(processed_item)
|
| 411 |
return processed_data
|
|
|
|
| 537 |
"user_scammers": [],
|
| 538 |
"server_scammers": [],
|
| 539 |
"dwc": [],
|
| 540 |
+
"trusted": [], # Add trusted key
|
| 541 |
"dupes": [],
|
|
|
|
| 542 |
}
|
| 543 |
current_errors = {} # Track errors for specific fetches/sheets
|
| 544 |
|
|
|
|
| 548 |
f"{quote_sheet_name(USER_SCAMMER_SHEET)}!{USER_SCAMMER_RANGE}",
|
| 549 |
f"{quote_sheet_name(SERVER_SCAMMER_SHEET)}!{SERVER_SCAMMER_RANGE}",
|
| 550 |
f"{quote_sheet_name(DWC_SHEET)}!{DWC_RANGE}",
|
| 551 |
+
f"{quote_sheet_name(TRUSTED_SHEET)}!{TRUSTED_RANGE}", # Add trusted range
|
| 552 |
]
|
| 553 |
scammer_dwc_processor_map = {
|
| 554 |
USER_SCAMMER_SHEET: process_user_scammer_data,
|
| 555 |
SERVER_SCAMMER_SHEET: process_server_scammer_data,
|
| 556 |
DWC_SHEET: process_dwc_data,
|
| 557 |
+
TRUSTED_SHEET: process_trusted_data, # Add trusted processor
|
| 558 |
}
|
| 559 |
scammer_dwc_target_key_map = {
|
| 560 |
USER_SCAMMER_SHEET: "user_scammers",
|
| 561 |
SERVER_SCAMMER_SHEET: "server_scammers",
|
| 562 |
DWC_SHEET: "dwc",
|
| 563 |
+
TRUSTED_SHEET: "trusted", # Add trusted target key
|
| 564 |
}
|
| 565 |
|
| 566 |
values_dupes_ranges = [f"{quote_sheet_name(DUPE_LIST_SHEET)}!{DUPE_LIST_RANGE}"]
|
|
|
|
| 662 |
# --- Fetch Roblox Avatars (for new data before comparison/webhook) ---
|
| 663 |
if not current_errors.get("scammer_dwc_batch") and \
|
| 664 |
not current_errors.get("process_user_scammers") and \
|
| 665 |
+
not current_errors.get("process_dwc") and \
|
| 666 |
+
not current_errors.get("process_trusted"): # Check trusted processing too
|
| 667 |
logger.info("Fetching Roblox avatars for newly processed data...")
|
| 668 |
avatar_tasks = []
|
| 669 |
+
entries_needing_avatars = new_cache_data.get("user_scammers", []) + new_cache_data.get("dwc", []) + new_cache_data.get("trusted", []) # Include trusted list
|
| 670 |
for entry in entries_needing_avatars:
|
| 671 |
if entry.get('roblox_username'):
|
| 672 |
avatar_tasks.append(fetch_avatar_for_entry_update(session, entry))
|
|
|
|
| 674 |
await asyncio.gather(*avatar_tasks) # Exceptions logged within helper
|
| 675 |
logger.info(f"Finished fetching avatars for {len(avatar_tasks)} potential new entries.")
|
| 676 |
else:
|
| 677 |
+
logger.warning("Skipping avatar fetching due to errors in fetching/processing scammer/dwc/trusted data.")
|
| 678 |
|
| 679 |
|
| 680 |
# --- Change Detection & Webhook Preparation (ONLY if cache is ready) ---
|
|
|
|
| 898 |
|
| 899 |
# Update scammer/DWC sections if their batch succeeded AND processing succeeded
|
| 900 |
if "scammer_dwc_batch" not in current_errors:
|
| 901 |
+
for key in ["user_scammers", "server_scammers", "dwc"]:
|
| 902 |
process_error_key = f"process_{key}"
|
|
|
|
| 903 |
if process_error_key not in current_errors:
|
| 904 |
+
if cache.get(key) != new_cache_data[key]:
|
| 905 |
+
cache[key] = new_cache_data[key]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 906 |
partial_update_details.append(key)
|
| 907 |
update_occurred = True
|
|
|
|
|
|
|
| 908 |
else:
|
| 909 |
+
logger.warning(f"Skipping update for '{key}' due to processing error.")
|
| 910 |
else:
|
| 911 |
+
logger.warning("Skipping update for 'user_scammers', 'server_scammers', 'dwc' due to batch fetch error.")
|
| 912 |
|
| 913 |
if update_occurred:
|
| 914 |
cache["last_updated"] = current_time # Mark partial update time
|
|
|
|
| 1008 |
"user_scammers": len(cache.get("user_scammers", [])),
|
| 1009 |
"server_scammers": len(cache.get("server_scammers", [])),
|
| 1010 |
"dwc_entries": len(cache.get("dwc", [])),
|
| 1011 |
+
"trusted_entries": len(cache.get("trusted", [])), # Add trusted count
|
| 1012 |
"duped_usernames": len(cache.get("dupes", [])),
|
|
|
|
| 1013 |
},
|
| 1014 |
"value_change_categories_in_last_cycle": len(cache.get("value_changes", {}))
|
| 1015 |
}
|
|
|
|
| 1059 |
|
| 1060 |
@app.get("/api/scammers")
|
| 1061 |
async def get_scammers():
|
| 1062 |
+
"""Get all scammer, DWC, and trusted data (users, servers, dwc, trusted) from cache"""
|
| 1063 |
check_cache_readiness()
|
| 1064 |
return {
|
| 1065 |
"users": cache.get("user_scammers", []),
|
| 1066 |
"servers": cache.get("server_scammers", []),
|
| 1067 |
"dwc": cache.get("dwc", []),
|
| 1068 |
+
"trusted": cache.get("trusted", []) # Include trusted list
|
| 1069 |
}
|
| 1070 |
|
| 1071 |
@app.get("/api/dupes")
|