jankv3
This commit is contained in:
parent
a1b175ca76
commit
33a32a331e
30
AGENT.md
30
AGENT.md
|
@ -25,3 +25,33 @@
|
||||||
- **Naming**: snake_case for variables/functions, PascalCase for classes
|
- **Naming**: snake_case for variables/functions, PascalCase for classes
|
||||||
- **Types**: Type hints required (`typing` module), dataclasses for data structures
|
- **Types**: Type hints required (`typing` module), dataclasses for data structures
|
||||||
- **Async**: All I/O operations use async/await, proper cleanup in finally blocks
|
- **Async**: All I/O operations use async/await, proper cleanup in finally blocks
|
||||||
|
|
||||||
|
## Recent Changes & Fixes
|
||||||
|
|
||||||
|
### Database Integration (2025-07-14)
|
||||||
|
- **✅ Remote MariaDB Support**: Added full support for remote MariaDB connections via .env credentials
|
||||||
|
- **✅ MariaDB->JSON Fallback**: Smart database factory that tries MariaDB first, falls back to JSON
|
||||||
|
- **✅ Dictionary Cursors**: Fixed asyncmy integration to return proper dictionary results instead of tuples
|
||||||
|
- **✅ Transaction Handling**: Proper async transaction management with START TRANSACTION/COMMIT/ROLLBACK
|
||||||
|
- **✅ Duplicate Key Handling**: Added INSERT IGNORE to prevent duplicate user-server entries
|
||||||
|
|
||||||
|
### Discord Data Collection Improvements
|
||||||
|
- **✅ Enhanced Bio Collection**: Multiple fallback methods for user bio extraction (direct, profile fetch, activity-based)
|
||||||
|
- **✅ Better Status Tracking**: Comprehensive status collection including platform-specific status (desktop/mobile/web)
|
||||||
|
- **✅ Activity Tracking**: Multi-activity support with proper type detection and formatting
|
||||||
|
- **✅ Discord API Fixes**: Fixed Guild.fetch_members() coroutine handling for discord.py-self
|
||||||
|
|
||||||
|
### CLI Enhancements
|
||||||
|
- **✅ Server Management Commands**: Added `servers`, `user-servers`, `server-users` commands for detailed server tracking
|
||||||
|
- **✅ Enhanced Search**: Search results now include bio, status, activity, and server membership info
|
||||||
|
- **✅ Better Formatting**: Improved output formatting with truncation and better readability
|
||||||
|
|
||||||
|
### Network & Connectivity
|
||||||
|
- **✅ Connection Testing**: Added early Discord connectivity testing with clear error messages
|
||||||
|
- **✅ Graceful Error Handling**: Better error messages for network issues and missing dependencies
|
||||||
|
|
||||||
|
## Production Status
|
||||||
|
- **Database**: ✅ Working (11 users collected from 1 server)
|
||||||
|
- **Discord Integration**: ✅ Working (logged in as _pixelparadox#0, 5 servers connected)
|
||||||
|
- **Data Collection**: ✅ Working (users, status, server membership being tracked)
|
||||||
|
- **Remote Storage**: ✅ Working (MariaDB at xargana.tr:3306, ~52KB database)
|
||||||
|
|
|
@ -17,7 +17,7 @@ server_membership = true
|
||||||
# Delay between API requests in seconds
|
# Delay between API requests in seconds
|
||||||
request_delay = 1.0
|
request_delay = 1.0
|
||||||
# Maximum requests per minute
|
# Maximum requests per minute
|
||||||
max_requests_per_minute = 30
|
max_requests_per_minute = 120
|
||||||
|
|
||||||
[monitoring]
|
[monitoring]
|
||||||
# List of specific server IDs to monitor (leave empty to monitor all)
|
# List of specific server IDs to monitor (leave empty to monitor all)
|
||||||
|
|
|
@ -107,8 +107,10 @@ class DiscordDataClient(discord.Client):
|
||||||
self.logger.info(f"Scanning server: {guild.name} ({guild.id})")
|
self.logger.info(f"Scanning server: {guild.name} ({guild.id})")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Get all members - different API for discord.py-self
|
# Get all members - discord.py-self API
|
||||||
members = [member async for member in guild.fetch_members()]
|
members = []
|
||||||
|
async for member in guild.fetch_members():
|
||||||
|
members.append(member)
|
||||||
|
|
||||||
for member in members:
|
for member in members:
|
||||||
if not member.bot:
|
if not member.bot:
|
||||||
|
@ -181,6 +183,7 @@ class DiscordDataClient(discord.Client):
|
||||||
# Method 1: Check if user object already has bio
|
# Method 1: Check if user object already has bio
|
||||||
if hasattr(user, 'bio') and user.bio:
|
if hasattr(user, 'bio') and user.bio:
|
||||||
bio = user.bio
|
bio = user.bio
|
||||||
|
self.logger.debug(f"Found bio via user.bio for {user.name}")
|
||||||
|
|
||||||
# Method 2: Try to get full user profile
|
# Method 2: Try to get full user profile
|
||||||
elif hasattr(user, 'id'):
|
elif hasattr(user, 'id'):
|
||||||
|
@ -188,16 +191,23 @@ class DiscordDataClient(discord.Client):
|
||||||
profile = await self.fetch_user(user.id)
|
profile = await self.fetch_user(user.id)
|
||||||
if hasattr(profile, 'bio') and profile.bio:
|
if hasattr(profile, 'bio') and profile.bio:
|
||||||
bio = profile.bio
|
bio = profile.bio
|
||||||
except Exception:
|
self.logger.debug(f"Found bio via profile fetch for {user.name}")
|
||||||
pass
|
else:
|
||||||
|
self.logger.debug(f"No bio found in profile for {user.name}")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.debug(f"Profile fetch failed for {user.name}: {e}")
|
||||||
|
|
||||||
# Method 3: Check for activities that might contain bio-like info
|
# Method 3: Check for activities that might contain bio-like info
|
||||||
if not bio and hasattr(user, 'activities'):
|
if not bio and hasattr(user, 'activities'):
|
||||||
for activity in user.activities:
|
for activity in user.activities:
|
||||||
if hasattr(activity, 'name') and activity.name and len(activity.name) > 20:
|
if hasattr(activity, 'name') and activity.name and len(activity.name) > 20:
|
||||||
bio = f"Activity: {activity.name}"
|
bio = f"Activity: {activity.name}"
|
||||||
|
self.logger.debug(f"Using activity as bio for {user.name}: {activity.name}")
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if not bio:
|
||||||
|
self.logger.debug(f"No bio found for user {user.name}")
|
||||||
|
|
||||||
return bio[:500] if bio else None # Limit bio length
|
return bio[:500] if bio else None # Limit bio length
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -413,7 +413,7 @@ class MariaDBDatabase:
|
||||||
if user_data.servers:
|
if user_data.servers:
|
||||||
for server_id in user_data.servers:
|
for server_id in user_data.servers:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO user_servers (user_id, server_id) VALUES (%s, %s)",
|
"INSERT IGNORE INTO user_servers (user_id, server_id) VALUES (%s, %s)",
|
||||||
(user_data.user_id, server_id)
|
(user_data.user_id, server_id)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -428,10 +428,11 @@ class MariaDBDatabase:
|
||||||
|
|
||||||
async def add_server_to_user(self, user_id: int, server_id: int):
|
async def add_server_to_user(self, user_id: int, server_id: int):
|
||||||
"""Add a server to user's server list."""
|
"""Add a server to user's server list."""
|
||||||
await self._execute_query("""
|
async with self.pool.cursor() as cursor:
|
||||||
INSERT IGNORE INTO user_servers (user_id, server_id)
|
await cursor.execute("""
|
||||||
VALUES (%s, %s)
|
INSERT IGNORE INTO user_servers (user_id, server_id)
|
||||||
""", (user_id, server_id))
|
VALUES (%s, %s)
|
||||||
|
""", (user_id, server_id))
|
||||||
|
|
||||||
async def get_all_users(self) -> List[UserData]:
|
async def get_all_users(self) -> List[UserData]:
|
||||||
"""Get all users from the database."""
|
"""Get all users from the database."""
|
||||||
|
@ -512,5 +513,5 @@ class MariaDBDatabase:
|
||||||
async def close(self):
|
async def close(self):
|
||||||
"""Close database connection."""
|
"""Close database connection."""
|
||||||
if self.pool:
|
if self.pool:
|
||||||
await self.pool.close()
|
self.pool.close()
|
||||||
self.logger.info("Database connection closed")
|
self.logger.info("Database connection closed")
|
||||||
|
|
Loading…
Reference in a new issue