File size: 4,731 Bytes
434f798
30462e3
c87648d
8dd1108
1f188d9
f6602f2
1f188d9
 
807606e
960e451
807606e
 
39d3eff
 
 
 
 
807606e
c6565e2
773ec73
807606e
 
 
d522acf
cbfe4d5
807606e
b80bf81
39d3eff
 
 
 
 
960e451
807606e
 
 
960e451
 
 
807606e
960e451
 
 
 
cbfe4d5
960e451
 
 
807606e
39d3eff
 
 
960e451
39d3eff
 
 
 
 
 
 
 
 
 
 
 
 
960e451
807606e
a56363d
ae4f533
39d3eff
 
 
 
 
 
 
ae4f533
 
5e34c0f
 
 
 
807606e
5e34c0f
 
807606e
2cf1870
5e34c0f
39d3eff
5e34c0f
807606e
39d3eff
5e34c0f
807606e
2cf1870
5e34c0f
 
807606e
2cf1870
5e34c0f
d522acf
39d3eff
 
 
 
 
139364e
807606e
39d3eff
 
139364e
960e451
 
807606e
39d3eff
 
 
 
 
 
 
960e451
807606e
 
 
 
 
 
139364e
39d3eff
139364e
 
960e451
139364e
960e451
 
cbfe4d5
 
 
 
 
960e451
 
 
 
 
807606e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import io
import sys
import asyncio
import discord
import aiohttp
import pandas as pd
import gradio as gr
import logging
from discord.ext import commands

# Set up logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)
logger = logging.getLogger(__name__)

DISCORD_TOKEN = os.environ.get("DISCORD_TOKEN", None)
if not DISCORD_TOKEN:
    logger.error("DISCORD_TOKEN not set. Exiting.")
    sys.exit(1)

intents = discord.Intents.all()
bot = commands.Bot(command_prefix="!", intents=intents)

# Cache guild/role globally
GUILD_ID = 879548962464493619
ROLE_ID = 900063512829755413
LUNAR_ID = 811235357663297546

async def process_row(row, guild, role):
    hf_user_name = row["hf_user_name"]
    if pd.notna(hf_user_name) and hf_user_name.lower() != "n/a":
        discord_id = row["discord_user_id"].strip("L")
        try:
            member = guild.get_member(int(discord_id))
        except Exception as e:
            logger.error(f"Error converting Discord ID {discord_id}: {e}")
            return

        if not member:
            return

        if role not in member.roles:
            try:
                await member.add_roles(role)
                logger.info(f"Role added to member: {member}")

                # Send confirmation to Lunar (optional)
                lunar = bot.get_user(LUNAR_ID)
                if lunar:
                    try:
                        await lunar.send(f"Verified role given to {member}!")
                    except discord.Forbidden:
                        logger.warning("Could not DM Lunar.")

                # DM the user (optional)
                try:
                    await member.send(
                        f"Verification successful! [{member} <---> {row['discord_user_name']}]"
                    )
                except discord.Forbidden:
                    logger.warning(f"Cannot DM {member} — DMs likely off.")

            except Exception as e:
                logger.error(f"Error processing member {member}: {e}")

async def give_verified_roles():
    guild = bot.get_guild(GUILD_ID)
    role = guild.get_role(ROLE_ID)

    if not guild or not role:
        logger.error("Guild or role not found. Exiting loop.")
        return

    while True:
        try:
            async with aiohttp.ClientSession() as session:
                try:
                    async with session.get(
                        "https://docs.google.com/spreadsheets/d/1C8aLqgCqLYcMiIFf-P_Aosaa03C_WLIB_UyqvjSdWg8/export?format=csv&gid=0",
                        timeout=10,
                    ) as response:
                        if response.status != 200:
                            logger.error(f"Failed to fetch CSV: HTTP {response.status}")
                            await asyncio.sleep(30)
                            continue

                        csv_data = await response.text()
                        global_df = await asyncio.to_thread(pd.read_csv, io.StringIO(csv_data))

                except asyncio.TimeoutError:
                    logger.error("CSV fetch timed out.")
                    await asyncio.sleep(30)
                    continue
                except Exception as e:
                    logger.error(f"Error fetching CSV: {e}")
                    await asyncio.sleep(30)
                    continue

            # Throttled loop to avoid hitting rate limits
            for _, row in global_df.iterrows():
                await process_row(row, guild, role)
                await asyncio.sleep(1.5)  # Delay between role assignments

        except Exception as e:
            logger.error(f"Error in give_verified_roles loop: {e}")

        await asyncio.sleep(30)

@bot.event
async def on_ready():
    logger.info(f"We have logged in as {bot.user}")
    guild = bot.get_guild(GUILD_ID)
    if guild:
        await guild.chunk()  # Cache members once on ready
        logger.info("Guild member cache initialized.")
    else:
        logger.warning("Guild not found on startup.")

    bot.loop.create_task(give_verified_roles())
    bot.loop.create_task(heartbeat())

async def heartbeat():
    while True:
        logger.info("Heartbeat: Bot is active.")
        await asyncio.sleep(60)

# Gradio setup
def greet(name):
    return "Hello " + name + "!"

demo = gr.Interface(fn=greet, inputs="text", outputs="text")

async def main():
    gradio_thread = asyncio.to_thread(demo.launch, share=False)
    await asyncio.gather(
        bot.start(DISCORD_TOKEN),
        gradio_thread
    )

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("Shutting down...")