import base64 import html from html.parser import HTMLParser import json import os import random import re import time import urllib.parse import urllib.request import urllib.error # --- CONFIGURATION --- MISTRAL_API_KEY = os.environ.get("MISTRAL_API_KEY", "CHTDjXRY5kE0odBx7jG064NccPJT3Cik") BOARD_URL = "https://indiachan.top" CATALOG_URL = f"{BOARD_URL}/boards/b/catalog" STATE_FILE = "bot_state.json" RUN_INTERVAL_SECONDS = 300 # 5 minutes exact delay step # --- TARGETED PERSONA PROMPT --- SYSTEM_INSTRUCTION = ( "You are an anonymous poster on an imageboard. " "Write ONLY the exact post content matching the tone of the thread. " "Do NOT include introductions, explanations, preambles, meta-commentary, " "or quotation marks around your answer. Be raw, direct, and completely in character." ) # --- NATIVE HTML PARSER (No External Libraries) --- class CatalogParser(HTMLParser): """Native event-driven parser to extract metadata and image links out of the catalog layout.""" def __init__(self): super().__init__() self.threads = [] self.current_thread = None self.in_preview_div = False self.div_depth = 0 def handle_starttag(self, tag, attrs): attr_dict = dict(attrs) # Identify the individual thread card container block if tag == "div" and attr_dict.get("class") == "post-container": self.current_thread = { "id": None, "replies": int(attr_dict.get("data-replies", 0)), "preview": "", "image_url": None } self.div_depth = 0 self.in_preview_div = False return if self.current_thread is not None: if tag == "div": self.div_depth += 1 # The preview text block sits inside an unclassed nested div block if self.div_depth >= 1 and "class" not in attr_dict: self.in_preview_div = True # Extract Thread ID from the target href structure elif tag == "a" and attr_dict.get("class") == "thread-catalog-link": href = attr_dict.get("href", "") if "/thread/" in href: self.current_thread["id"] = href.split("/thread/")[-1].split("#")[0] # Catch the thread thumbnail image URL elif tag == "img" and "thread-img" in attr_dict.get("class", ""): src = attr_dict.get("src", "") if src: # Construct an absolute URL if the path is relative self.current_thread["image_url"] = src if src.startswith("http") else f"{BOARD_URL}{src}" def handle_data(self, data): if self.current_thread and self.in_preview_div: self.current_thread["preview"] += data def handle_endtag(self, tag): if self.current_thread is not None: if tag == "div": if self.in_preview_div: self.in_preview_div = False self.div_depth -= 1 if self.div_depth < 0: # Outer container boundary closed, finalize the current item self.current_thread["preview"] = html.unescape(self.current_thread["preview"]).strip() if self.current_thread["id"]: self.threads.append(self.current_thread) self.current_thread = None # --- BOT IMPLEMENTATION HUB --- class DynamicImageboardBot: def __init__(self): self.state = self.load_state() def load_state(self): """Loads state from file or initializes structural defaults.""" if os.path.exists(STATE_FILE): try: with open(STATE_FILE, "r") as f: return json.load(f) except Exception: print("[-] State file corrupted. Re-initializing...") return {"replied_threads": [], "learned_keywords": {}} def save_state(self, current_catalog_size: int = 100): """Maintains structural size limits and updates the state file atomically.""" if len(self.state["replied_threads"]) > current_catalog_size: self.state["replied_threads"] = self.state["replied_threads"][-current_catalog_size:] # Atomic replacement strategies safeguard json integrity from random process exits temp_file = f"{STATE_FILE}.tmp" try: with open(temp_file, "w") as f: json.dump(self.state, f, indent=4) os.replace(temp_file, STATE_FILE) except Exception as e: print(f"[-] Failed to write state file safely: {e}") def fetch_live_page(self, url: str) -> str: """Downloads HTML layout sequences over basic network streams natively.""" req = urllib.request.Request(url) req.add_header( "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", ) try: with urllib.request.urlopen(req, timeout=15) as response: return response.read().decode("utf-8", errors="ignore") except Exception as e: print(f"[-] Network connection block fault context ({url}): {e}") return "" def download_image_as_base64(self, img_url: str) -> str: """Downloads binary graphics context streams directly into data URI strings.""" if not img_url: return None req = urllib.request.Request(img_url) req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") try: with urllib.request.urlopen(req, timeout=10) as response: content_type = response.headers.get("Content-Type", "image/jpeg") img_data = response.read() b64_data = base64.b64encode(img_data).decode("utf-8") print(f"[+] Encoded image asset wrapper payload ({len(img_data)} bytes)") return f"data:{content_type};base64,{b64_data}" except Exception as e: print(f"[-] Vision resource compilation skipped for URI ({img_url}): {e}") return None def evaluate_threads(self, threads: list) -> dict: """Calculates targeted threat weights using dynamic learning history metrics.""" eligible = [t for t in threads if t["id"] not in self.state["replied_threads"]] if not eligible: return None scored_threads = [] for t in eligible: score = 50 + random.randint(-15, 15) # Target small-to-mid discussions; avoid oversized mega-threads if 2 < t["replies"] < 40: score += 20 elif t["replies"] >= 40: score -= 15 # Historical interest multipliers words = re.findall(r"\w+", t["preview"].lower()) for word in words: if word in self.state["learned_keywords"]: score += min(self.state["learned_keywords"][word], 25) scored_threads.append((score, t)) scored_threads.sort(key=lambda x: x[0], reverse=True) chosen_thread = scored_threads[0][1] # Self-Learning Feedback loop updates chosen_words = set(re.findall(r"\w+", chosen_thread["preview"].lower())) for w in chosen_words: if len(w) > 4: current_weight = self.state["learned_keywords"].get(w, 0) self.state["learned_keywords"][w] = min(current_weight + 2, 50) # Keyword decay cycle over broad run cycles if random.random() < 0.10: for k in list(self.state["learned_keywords"].keys()): self.state["learned_keywords"][k] -= 1 if self.state["learned_keywords"][k] <= 0: del self.state["learned_keywords"][k] return chosen_thread def query_mistral_multimodal(self, prompt: str, image_base64: str = None) -> str: """Submits textual prompts merged with raw vision blocks to Mistral API endpoints.""" url = "https://api.mistral.ai/v1/chat/completions" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {MISTRAL_API_KEY}", } user_content = [{"type": "text", "text": prompt}] if image_base64: user_content.append({ "type": "image_url", "image_url": { "url": image_base64 } }) data = { "model": "pixtral-12b-latest", "messages": [ { "role": "system", "content": SYSTEM_INSTRUCTION }, { "role": "user", "content": user_content }, ], "temperature": 0.85, } req = urllib.request.Request( url, data=json.dumps(data).encode("utf-8"), headers=headers ) try: with urllib.request.urlopen(req) as response: res = json.loads(response.read().decode("utf-8")) return res["choices"][0]["message"]["content"].strip() except urllib.error.HTTPError as http_err: error_body = http_err.read().decode("utf-8", errors="ignore") print(f"[-] API rejected execution structure: {http_err.code} - {error_body}") return "" except Exception as e: print(f"[-] AI generation failed completely during token exchange: {e}") return "" def submit_reply(self, thread_id: str, content: str, catalog_capacity: int): """Transmits raw response content directly over target data webhook frames.""" endpoint = f"{BOARD_URL}/boards/b/thread/{thread_id}/reply" # Added delete_password parameter field directly to payload mapping payload = { "content": content, "delete_password": "apnimaasepuch" } data = urllib.parse.urlencode(payload).encode("utf-8") req = urllib.request.Request(endpoint, data=data) req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36") req.add_header("Content-Type", "application/x-www-form-urlencoded") req.add_header("Content-Length", str(len(data))) req.add_header("Referer", f"{BOARD_URL}/boards/b/thread/{thread_id}") try: with urllib.request.urlopen(req, timeout=15) as r: response_code = r.getcode() if response_code in [200, 201]: print(f"[+] Simulation transaction completed for Thread #{thread_id}!") self.state["replied_threads"].append(thread_id) self.save_state(current_catalog_size=catalog_capacity) else: print(f"[-] Target instance rejected payload with status code: {response_code}") except Exception as e: print(f"[-] Reply submission pipeline fault event handled: {e}") def run_one_iteration(self): """Sequences target thread retrieval parsing steps, multimodal generation, and submission.""" print("\n[*] Synchronizing remote catalog live stream data views...") catalog_html = self.fetch_live_page(CATALOG_URL) if not catalog_html: return parser = CatalogParser() parser.feed(catalog_html) threads = parser.threads catalog_total_capacity = len(threads) if threads else 100 print(f"[*] Parsed {catalog_total_capacity} active catalog thread entries.") chosen_thread = self.evaluate_threads(threads) if not chosen_thread: print("[*] No target entries chosen during this execution block run step.") return print(f"[*] Selected Target Thread: #{chosen_thread['id']}") base64_image = None if chosen_thread["image_url"]: if not chosen_thread["image_url"].lower().endswith(".gif"): print(f"[*] Processing visual information element: {chosen_thread['image_url']}") base64_image = self.download_image_as_base64(chosen_thread["image_url"]) else: print(f"[*] Skipping vision evaluation for animated GIF element: {chosen_thread['image_url']}") prompt = ( f"Context: Imageboard discussion thread.\n" f"OP Text Post: '{chosen_thread['preview']}'\n\n" f"Analyze the thread message context along with the attached image thumbnail if available. " f"Draft a short response compatible with imageboard board culture.\n" f"CRITICAL RULES:\n" f"- Output ONLY the final response text.\n" f"- Do NOT wrap text in quotation marks.\n" f"- Avoid explanatory text, preambles, or conversational introductions entirely." ) ai_response = self.query_mistral_multimodal(prompt, base64_image) if ai_response: final_text = f">>OP\n{ai_response}" self.submit_reply(chosen_thread["id"], final_text, catalog_total_capacity) if __name__ == "__main__": bot = DynamicImageboardBot() print("[+] Core engine synchronized natively... Terminate execution loops via [Ctrl+C]") while True: try: bot.run_one_iteration() except Exception as global_err: print(f"[-] Global application level monitoring fault caught: {global_err}") print(f"[*] Sleeping for {RUN_INTERVAL_SECONDS // 60} minutes...") time.sleep(RUN_INTERVAL_SECONDS)