diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..40b8278
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,60 @@
+# Python
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Virtual Environments
+venv/
+env/
+ENV/
+env.bak/
+venv.bak/
+
+# Instaloader Session Files
+session-*
+*.session
+
+# Downloaded Instagram Content (in specific folder)
+downloads/
+instagram_content/
+*.json.xz
+*.txt.xz
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+.DS_Store
+
+# Credentials (if any config files are added later)
+config.ini
+.env
+credentials.json
+
+# Logs
+*.log
+
+# OS
+.DS_Store
+Thumbs.db
diff --git a/README.md b/README.md
index bd9bf0b..8b309cc 100644
--- a/README.md
+++ b/README.md
@@ -1,81 +1,1074 @@
-### INSTA-OSINT 📋
-is a tool to find as much information as possible on Instagram accounts, such as username, full username, post target, account type, number of followers, number of followings and so on.
+# 📸 Instagram OSINT Tool v2.0
-
+> Advanced Open Source Intelligence gathering tool for Instagram with interactive menus, analytics engine, batch processing, and multi-format exports.
-This tool is an update from OsintIG on my first account
-***DO NOT COPY OR RECODE THIS TOOL WITHOUT PERMISSION!!!***
-
-***DILARANG RECODE TOOL INI TANPA IZIN DARI ADMINN!!!!***
+---
-
-:zap: Version 1.1.0 :
-- INSTA-OSINT V1.1.0
-
+## 🌟 Overview
-### Note 📍
-to use this tool you have to prepare a `dummy account`, don't use a real account if you don't want it to expire
-do not use for illegal actions because the admin will not be responsible
+Instagram OSINT is a comprehensive intelligence gathering tool that combines session persistence, advanced analytics, database storage, and beautiful **interactive terminal UI** to analyze Instagram profiles efficiently. Whether you're a researcher, security analyst, or enthusiast, this tool provides powerful insights into Instagram account patterns and behaviors.
-### Instalation on Linux (.deb)
-```
-sudo apt update && sudo apt upgrade
-sudo apt install git
-sudo apt install python3
-```
+**Current Version:** 2.0.0
+**Last Updated:** December 2025
+**Interface:** Fully Interactive Menu System
+
+---
+
+## 📺 Terminal UI - Screenshots
+
+### 1. Login Screen
+Beautiful ASCII art banner with secure password input (hidden characters)
+
+
+
+---
+
+### 2. Two-Factor Authentication
+Seamless 2FA support for protected accounts
+
+
+
+---
+
+### 3. Features Configuration Menu
+Choose what you want to do - downloads, analytics, database storage
+
+
+
+---
+
+### 4. Export Format Selection
+Multiple export options - JSON, CSV, HTML or all combined
+
+
+
+---
+
+### 5. Data Limits Configuration
+Control how much data to fetch for performance optimization
+
+
+
+---
+
+### 6. Configuration Summary
+Review your selections before processing begins
+
+
+
+---
+
+### 7. Profile Processing
+Real-time progress indicators and colorful status messages
+
+
+
+---
+
+### 8. HTML Report Output
+Beautiful interactive reports with all profile data
+
+
+
+---
+
+## ✨ Key Features
+
+### 🎯 Interactive Menu System
+- **No Command-Line Arguments Needed** - Everything is menu-driven
+- **Step-by-Step Guidance** - Clear prompts for every decision
+- **Visual Menus** - Colorful, numbered options
+- **Input Validation** - Prevents errors with helpful messages
+- **Confirmation Prompts** - Review settings before execution
+
+### 🔐 Authentication & Security
+- **Hidden Password Input** - Passwords never shown on screen
+- **Two-Factor Authentication Support** - Handle 2FA seamlessly
+- **Session Persistence** - Save sessions to avoid re-authentication
+- **Smart Session Management** - Auto-load previous sessions
+
+### 📊 Analytics Engine
+- **Engagement Rate Calculation** - Followers per post metric
+- **Follower Ratio Analysis** - Followers vs Following comparison
+- **Risk Score Detection** - Identify suspicious accounts (0-100 scale)
+- **Profile Classification** - Detect Business, Influencer, Bot, Regular accounts
+- **Growth Tracking** - Historical data and trend analysis
+
+### 📤 Export Capabilities
+- **JSON Export** - Complete structured data with metadata
+- **CSV Export** - Spreadsheet-ready format (profile, followers, following)
+- **HTML Reports** - Interactive visual reports with styling
+- **Multi-format Exports** - Export to multiple formats simultaneously
+
+### 💾 Database Backend (SQLite)
+- Store profile snapshots with timestamps
+- Track follower/following changes over time
+- Cache analytics results for quick queries
+- Generate growth statistics and trends
+- Historical profile comparisons
+
+### 🔄 Batch Processing
+- Process multiple profiles in single run
+- Enter targets interactively or from file
+- Compare profiles side-by-side
+- Find mutual followers/following between accounts
+- Rate-limited to respect Instagram API
+
+### 🎨 Beautiful Terminal UI
+- Colorful ASCII banner and messages
+- Color-coded status indicators (✓ ✗ !)
+- Loading animations and progress indicators
+- Organized, readable output format
+- Professional terminal interface
+
+---
+
+## 📋 Table of Contents
-### Instalation on Termux
+1. [Installation](#-installation)
+2. [Quick Start](#-quick-start)
+3. [Interactive Menu Guide](#-interactive-menu-guide)
+4. [Features in Detail](#-features-in-detail)
+5. [Export Formats](#-export-formats)
+6. [Analytics Explained](#-analytics-explained)
+7. [Database Features](#-database-features)
+8. [Module Architecture](#-module-architecture)
+9. [Legal & Disclaimer](#-legal--disclaimer)
+
+---
+
+## 🚀 Installation
+
+### For Desktop/Laptop (Linux, macOS, Windows)
+
+#### Prerequisites
+- Python 3.8+
+- pip package manager
+- Instagram account (for authentication)
+
+#### Setup
+
+```bash
+# Clone repository
+git clone https://github.com/Adamo08/INSTA-OSINT.git
+cd INSTA-OSINT
+
+# Create virtual environment (recommended)
+python3 -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+
+# Install dependencies
+pip install -r requirements.txt
```
+
+---
+
+### 📱 For Mobile (Android via Termux)
+
+Yes! This tool works perfectly on Android phones using **Termux**!
+
+#### Step 1: Install Termux
+Download Termux from [F-Droid](https://f-droid.org/packages/com.termux/) (recommended) or Google Play Store
+
+#### Step 2: Setup Termux Environment
+
+```bash
+# Update packages
pkg update && pkg upgrade
-pkg install git
-pkg install python3
-```
-### Use Tool
+# Install required packages
+pkg install python git
+
+# Install pip
+pip install --upgrade pip
```
-git clone https://github.com/HunxByts/INSTA-OSINT.git
+
+#### Step 3: Clone and Setup
+
+```bash
+# Get storage permissions (optional, for saving files)
+termux-setup-storage
+
+# Clone repository
+git clone https://github.com/Adamo08/INSTA-OSINT.git
cd INSTA-OSINT
-pip3 install -r requirements.txt
+
+# Install dependencies
+pip install -r requirements.txt
+```
+
+#### Step 4: Run the Tool
+
+```bash
+python instaOSINT.py
+```
+
+#### 📱 Mobile Tips
+- Use landscape mode for better visibility
+- Swipe keyboard to navigate terminal
+- Files are saved in `/storage/emulated/0/` if using termux-setup-storage
+- Session files persist between runs (no need to login every time)
+- Works on mobile data or WiFi
+- Can run in background with Termux:Boot addon
+
+#### Termux Keyboard Shortcuts
+- `Volume Down + C` = Ctrl+C (cancel/exit)
+- `Volume Down + L` = Clear screen
+- `Volume Down + Z` = Suspend process
+
+---
+
+### Dependencies
+- `instaloader` - Instagram scraping library
+- Built-in Python libraries (no external dependencies for UI)
+
+---
+
+## ⚡ Quick Start
+
+### Simply Run the Tool
+```bash
python3 instaOSINT.py
```
+**That's it!** The tool will guide you through everything with interactive menus.
+
+### What Happens Next?
+
+1. **🔐 Login Screen** - Enter your Instagram credentials (password is hidden)
+2. **📋 Main Menu** - Choose what you want to do:
+ - Single Profile Analysis
+ - Batch Profile Analysis
+ - Compare Profiles
+ - View Database History
+3. **⚙️ Configuration Menus** - Select features, export formats, and limits
+4. **📊 Summary** - Review your choices
+5. **🚀 Processing** - Watch real-time progress
+6. **✅ Results** - Get exported files and analytics
+
+---
+
+## 🎮 Interactive Menu Guide
+
+### Main Menu Options
+
+When you run the tool, you'll see:
+ -p mypassword \
+ -t targetusername \
+ --analyze \
+
+**1. Single Profile Analysis** - Analyze one Instagram account
+ - Download posts & highlights
+ - Calculate analytics
+ - Export in multiple formats
+
+**2. Batch Profile Analysis** - Process multiple accounts
+ - Enter usernames one by one
+ - Or provide them via file
+ - Process sequentially with rate limiting
+
+**3. Compare Profiles** - Find connections between accounts
+ - Mutual followers analysis
+ - Profile similarity scoring
+ - Network mapping
+
+**4. View Database History** - Check stored data
+ - Query past analyses
+ - View growth statistics
+ - Export historical reports
+
+**5. Exit** - Close the tool
+
+### Features Configuration Menu
+
+After selecting a profile, configure what to do:
+
+**1. Download Posts & Highlights** ⚠️ May take time
+ - Downloads all media from profile
+ - Saves to local directory
+
+**2. Run Analytics** 📊 Calculate metrics
+ - Engagement rate
+ - Follower ratio
+ - Risk scoring
+ - Profile classification
+
+**3. Save to Database** 💾 Track history
+ - Store profile snapshot
+ - Enable growth tracking
+ - Historical comparisons
+
+**4. All Features** - Enable everything above
+
+**5. None (Quick Mode)** - Basic info only
+ - Fast execution
+ - Just profile metadata
+ - No downloads or analytics
+
+### Export Format Menu
+
+Choose how to save your data:
+
+**1. JSON only** - Structured data format
+**2. CSV only** - Spreadsheet format (3 files)
+**3. HTML only** - Visual report in browser
+**4. JSON + CSV** - Both formats
+**5. JSON + HTML** - Structured + Visual
+**6. All formats** - JSON + CSV + HTML (recommended)
+
+### Data Limits Menu
+
+Control performance by limiting data fetched:
+
+**1. No limits** - Fetch everything (slow for large accounts)
+**2. Limit to 100 each** - Quick analysis
+**3. Limit to 500 each** - Balanced
+**4. Limit to 1000 each** - Comprehensive
+**5. Custom limits** - Enter your own numbers
+
+---
+
+## 🎯 Step-by-Step Walkthrough
+
+### Example: Analyzing a Single Profile
+
+1. **Start the tool:**
+ ```bash
+ python3 instaOSINT.py
+ ```
+
+2. **Login** (first time or if session expired):
+ - Enter your Instagram username
+ - Enter password (hidden input - you won't see characters)
+ - If 2FA is enabled, enter the 6-digit code
+
+3. **Main Menu appears:**
+ - Select **[1] Single Profile Analysis**
+
+4. **Enter target:**
+ - Type the username you want to analyze
+ - Example: `targetusername`
+
+5. **Features Configuration:**
+ - Select **[2] Run Analytics** for metrics
+ - Or **[4] All Features** for complete analysis
+
+6. **Export Format:**
+ - Select **[6] All formats** for complete export
+
+7. **Data Limits:**
+ - Select **[3] Limit to 500 each** for balanced performance
+
+8. **Configuration Summary:**
+ - Review your selections
+ - Confirm to proceed (y/n)
+
+9. **Processing:**
+ - Watch real-time progress indicators
+ - Colored status messages show each step
+ - ✓ marks successful completion
+
+10. **Results:**
+ - Files exported to current directory
+ - Open HTML report in browser
+ - Check JSON for structured data
+ - Import CSV into spreadsheet
+
+---
+
+## 🔄 Batch Processing Example
+
+Process multiple accounts efficiently:
+
+1. **Create targets file:**
+ ```bash
+ cat > targets.txt << EOF
+ username1
+ username2
+ username3
+ EOF
+ ```
+
+2. **Run tool:**
+ ```bash
+ python3 instaOSINT.py
+ ```
+
+3. **Select [2] Batch Profile Analysis**
+
+4. **Choose input method:**
+ - Select "Load from file"
+ - Enter filename: `targets.txt`
+
+5. **Configure options:**
+ - Features: **[2] Run Analytics**
+ - Export: **[1] JSON only**
+ - Limits: **[2] Limit to 100 each** (for speed)
+
+6. **Watch processing:**
+ - Progress: [1/3], [2/3], [3/3]
+ - Each profile processed sequentially
+ - 2-second delay between profiles (rate limiting)
+
+7. **Results:**
+ - 3 JSON files created (one per profile)
+ - Summary statistics displayed
+ - All data in database if enabled
+
+---
+
+## 💡 Usage Tips
+
+### Best Practices
+
+**For Quick Analysis:**
+- Use **Quick Mode** (Feature option 5)
+- Set **Limit to 100** on followers/following
+- Export **JSON only**
+
+**For Comprehensive Research:**
+- Enable **All Features**
+- Use **No Limits** (option 1)
+- Export **All formats**
+- Enable **Database storage**
+
+**For Large Accounts (100K+ followers):**
+- Use **Custom Limits** with reasonable numbers
+- Skip downloads (**Quick Mode**)
+- Process during off-peak hours
+
+**For Regular Monitoring:**
+- Enable **Database storage**
+- Run weekly/monthly
+- Use **Quick Mode** for speed
+- Track growth via database queries
+
+### Session Management
+
+**First Run:**
+- Requires username + password
+- 2FA if enabled
+- Session saved automatically
+
+**Subsequent Runs:**
+- Session auto-loaded
+- No password needed
+- No 2FA prompt
+- Instant authentication ✓
+
+**Clear Sessions:**
+```bash
+rm session-*
+```
+
+---
+
+## 🎯 Features in Detail
+
+### Session Persistence
+Automatically saves authentication sessions to `session-{username}` files.
+
+**Benefits:**
+- No need to re-enter credentials
+- Skip 2FA on subsequent runs
+- Faster authentication
+- Secure token storage
+
+**How it works:**
+```
+First Run: Username + Password → Authenticate → Save Session
+Second Run: Load Session → Authenticate Instantly ✓
+```
+
+### Two-Factor Authentication
+Seamlessly handles 2FA protected accounts.
+
+**Process:**
+1. Script detects 2FA requirement
+2. Prompts for 6-digit code
+3. Accepts code from authenticator app or SMS
+4. Saves session with 2FA tokens
+5. Future runs skip 2FA entirely
+
+### Security Features
+- **Hidden Password Input** - Uses getpass module, no echo
+- **Session Encryption** - Tokens stored securely
+- **No Password Storage** - Never saves plain-text passwords
+- **Local Session Files** - No cloud storage
+
+### Error Handling
+Graceful error handling for:
+- Non-existent profiles
+- Private accounts (limited data)
+- Rate limiting (automatic delays)
+- Network errors
+- Invalid credentials
+
+---
+
+## 💾 Database Features
+
+### Automatic Database Creation
+First run creates `osint_data.db` with optimized schema.
+
+### Tables
+
+#### profiles
+Snapshots of profile metadata:
+- Username, user ID, full name
+- Bio, external URL
+- Privacy settings, account type
+- Follower/following/post counts
+- Timestamps
+
+#### followers
+Historical follower records:
+- Profile being followed
+- Follower details (username, ID, name)
+- Timestamp of recording
+
+#### profile_history
+Growth tracking over time:
+- Follower count snapshot
+- Following count snapshot
+- Post count snapshot
+- Recorded timestamp
+
+#### analytics_cache
+Cached analytics results:
+- Engagement metrics
+- Risk scores
+- Profile classification
+- Calculation timestamp
+
+### Growth Tracking Example
+
+Run the same profile analysis periodically:
+
+```bash
+# Day 1
+python3 instaOSINT.py -u myuser -p mypass -t target --db
+
+# Day 7 (one week later)
+python3 instaOSINT.py -u myuser -p mypass -t target --db
+```
+
+Database automatically tracks changes. Query growth:
+```python
+from database import OsintDatabase
+db = OsintDatabase()
+growth = db.get_growth_stats('target')
+print(f"Follower change: +{growth['followers_change']}")
+```
+
+📸 **SCREENSHOT**: Show osint_data.db file in file explorer and terminal output showing growth statistics query result
+
+---
+
+## 📤 Export Formats
+
+### JSON Export
+**File:** `{username}_data_YYYYMMDD_HHMMSS.json`
+
+**Sample Structure:**
+```json
+{
+ "export_date": "2025-12-30T12:34:56.789000",
+ "profile": {
+ "username": "targetuser",
+ "full_name": "Target User Name",
+ "user_id": 123456789,
+ "biography": "User bio",
+ "followers_count": 5000,
+ "following_count": 1200,
+ "posts_count": 250
+ },
+ "followers": [
+ {"username": "follower1", "user_id": 111111111, "full_name": "Follower Name"}
+ ],
+ "following": [...],
+ "analytics": {
+ "engagement_rate": 2.5,
+ "follower_ratio": 4.17,
+ "risk_score": 12,
+ "profile_type": "Influencer"
+ }
+}
+```
+
+📸 **SCREENSHOT**: Open JSON file in text editor and show formatted output (capture first 50 lines)
+
+### CSV Export
+**Files Generated:**
+- `{username}_profile_TIMESTAMP.csv` - Profile metadata
+- `{username}_followers_TIMESTAMP.csv` - Followers list
+- `{username}_following_TIMESTAMP.csv` - Following list
+
+📸 **SCREENSHOT**: Show file explorer with all three CSV files generated
+
+### HTML Report
+**File:** `{username}_report_YYYYMMDD_HHMMSS.html`
+
+**Features:**
+- Professional styling with Instagram branding
+- Profile information card
+- Analytics dashboard
+- Responsive design
+- Searchable tables
+- Print-friendly layout
+
+📸 **SCREENSHOT**: Open HTML report in web browser (Firefox/Chrome) showing full page with profile info, analytics section, and tables
+
+---
+
+## 📊 Analytics Explained
+
+### Engagement Rate
+```
+Formula: Followers / Posts
+```
+
+**Example:** 1000 followers / 100 posts = 10 followers per post
+
+### Follower Ratio
+```
+Formula: Followers / Following
+```
+
+**Example:** 1000 followers / 200 following = 5.0 ratio
+
+### Risk Score (0-100)
+Calculated risk of account being suspicious, bot, or fake.
+
+**Factors:**
+- Very high following count (following 2x+ followers)
+- No posts but many followers (bot indicator)
+- Extremely low engagement
+- Private with unusual follower growth
+
+### Profile Type Classification
+- **Business Account** - Has business category set
+- **Influencer** - 10,000+ followers
+- **Private Account** - Privacy enabled
+- **Regular Account** - Standard user
+- **Inactive/Potential Bot** - 0 posts despite followers
+
+### Example Analytics Output
+
+```
+📊 ANALYTICS
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+✓ Profile Type : Influencer
+✓ Engagement Rate : 2.5
+✓ Follower Ratio : 4.17
+✓ Risk Score : 15/100 (Low Risk)
+✓ Posts per Follower : 0.05
+✓ Following % : 24.0%
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+```
+
+📸 **SCREENSHOT**: Run analysis with `--analyze` and capture the colorful analytics output section
+
+---
+
+## 🏗️ Module Architecture
+
+### processor.py
+Core OSINT operations including authentication, profile fetching, batch processing, and export coordination.
+
+### analyzer.py
+Analytics calculations including engagement metrics, risk scoring, profile classification, and comparative analysis.
+
+### exporter.py
+Multi-format export supporting JSON, CSV, and HTML report generation with professional formatting.
+
+### database.py
+SQLite backend for persistent storage, historical tracking, and growth statistics.
+
+### cli.py
+Command-line interface with argument parsing, validation, and comprehensive help documentation.
+
+### utils.py
+Helper functions for colored output, formatting, animations, and status messages.
+
+---
+
+## 💡 Examples
+
+### Example 1: Analyze Single Influencer
+
+```bash
+python3 instaOSINT.py \
+ -u myusername \
+ -p mypassword \
+ -t cristiano \
+ --analyze \
+ -o json,html
+```
+
+**Note:** When running interactively, passwords are **hidden** for security (masked input).
+
+📸 **SCREENSHOT**: Run this command and capture console showing analysis results with colorful output
+
+### Example 2: Batch Processing from File
+
+```bash
+cat > targets.txt << EOF
+username1
+username2
+username3
+EOF
+
+python3 instaOSINT.py \
+ -u myusername \
+ -p mypassword \
+ -f targets.txt \
+ --analyze \
+ --db
+```
+
+📸 **SCREENSHOT**: Capture the batch processing progress showing all three profiles being processed
+
+### Example 3: Track Growth Over Time
+
+```bash
+# Day 1
+python3 instaOSINT.py -u myuser -p mypass -t target --db
+
+# Day 8
+python3 instaOSINT.py -u myuser -p mypass -t target --db
+
+# Query results
+python3 << 'EOF'
+from database import OsintDatabase
+db = OsintDatabase()
+growth = db.get_growth_stats('target')
+print(growth)
+EOF
+```
+
+📸 **SCREENSHOT**: Show the Python query output displaying growth statistics
+
+### Example 4: Multi-Format Export
+
+```bash
+python3 instaOSINT.py \
+ -u myusername \
+ -p mypassword \
+ -t targetusername \
+ -o json,csv,html \
+ --analyze
+```
+
+📸 **SCREENSHOT**: Show file explorer with all exported files (JSON, 3 CSVs, HTML)
+
+---
+
+## 🔧 CLI Reference
+
+### Full Help
+```bash
+python3 instaOSINT.py --help
+```
+
+### Essential Arguments
+
+```bash
+# Authentication
+-u, --username USERNAME Your Instagram username
+-p, --password PASSWORD Your Instagram password
+--no-session Don't use saved sessions
+
+# Target Selection
+-t, --target TARGET Single target username
+-f, --file FILE File with target list
+
+# Output Options
+-o, --output OUTPUT Export formats: json,csv,html
+-d, --dir DIR Output directory
+
+# Features
+--db Store in database
+--analyze Calculate analytics
+--compare Compare profiles
+--no-download Skip downloads
+
+# Performance
+--limit-followers N Max followers to fetch
+--limit-following N Max following to fetch
+--quiet Minimize output
+```
+
+📸 **SCREENSHOT**: Capture the help output from `python3 instaOSINT.py --help`
+
+---
+
+## 🎨 Terminal Output Examples
+
+### Login & Authentication
+```
+📱 Instagram OSINT Tool v2.0
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+[+] LOGIN YOUR INSTAGRAM ACCOUNT
+
+Enter Instagram username: myusername
+Enter Instagram password: ••••••••
+
+[✓] Session loaded successfully!
+[✓] Login successful!
+```
+
+📸 **SCREENSHOT**: Capture the colorful login screen with ASCII art banner
+
+### Profile Analysis Output
+```
+📊 PROCESSING targetusername
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+[+] Full Name: Target User Name
+[+] ID: 123456789
+[+] Followers: 5,000
+[+] Following: 1,200
+[+] Posts: 250
+
+[✓] Fetched 5000 followers
+[✓] Fetched 1200 following
+
+📊 ANALYTICS
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+[+] Profile Type: Influencer
+[+] Engagement Rate: 2.5
+[+] Follower Ratio: 4.17
+[+] Risk Score: 15/100 (Low Risk)
+
+[✓] Exported to: targetuser_data_20251230_123456.json
+```
+
+📸 **SCREENSHOT**: Run a profile analysis and capture full colored output
+
+### Batch Processing Progress
+```
+🔄 BATCH PROCESSING 3 PROFILES
+━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
+
+[1/3] Processing username1...
+✓ Completed in 15s
+
+[2/3] Processing username2...
+✓ Completed in 12s
+
+[3/3] Processing username3...
+✓ Completed in 18s
+
+✓ Batch complete! Total: 45s
+✓ All data saved to database
+```
+
+📸 **SCREENSHOT**: Run batch processing and capture the progress output
+
+---
+
+## 📋 Requirements
+
+### System Requirements
+- Python 3.8 or higher
+- 50MB disk space minimum
+- Internet connection
+- Instagram account
+
+### Python Dependencies
+```
+instaloader>=4.12.0
+requests>=2.28.0
+```
+
+---
+
+## ⚙️ Configuration
+
+### Session Files
+Sessions stored as: `session-{username}`
+
+**Clear sessions:**
+```bash
+rm session-*
+```
+
+### Database File
+Auto-created as: `osint_data.db`
+
+**Reset database:**
+```bash
+rm osint_data.db
+```
+
+### Output Directory
+```bash
+python3 instaOSINT.py -u user -p pass -t target -d /custom/path
+```
+
+---
+
+## 🔒 Security & Best Practices
+
+### Password Security
+✅ **Interactive Mode:**
+- Passwords are **masked** during input (not visible on screen)
+- Uses Python's `getpass` module for secure input
+- Characters replaced with dots/asterisks
+- No password echoing to terminal
+
+✅ **CLI Mode:**
+- Pass credentials via command-line arguments
+- Credentials not stored in shell history (use space prefix on some shells)
+- Session tokens stored locally only
+
+### Credentials Handling
+- Never commit passwords to version control
+- Use environment variables for automation
+- Session tokens are local only
+- Use your own account
+
+### Rate Limiting
+- Tool adds automatic delays between requests
+- Don't run multiple instances simultaneously
+- Respect Instagram's Terms of Service
+- Monitor for IP blocks
+
+### Data Privacy
+- Content stored locally
+- Database contains snapshots
+- Export files are not encrypted
+- Clean up old files regularly
+
+---
+
+## ⚠️ Legal & Disclaimer
+
+**This tool is for educational and authorized research purposes only.**
+
+### Important
+1. **Terms of Service**: Using this may violate Instagram's ToS
+2. **Legal Compliance**: Follow all applicable laws
+3. **No Liability**: Authors not responsible for consequences
+4. **Authorization Only**: Analyze accounts you have permission for
+
+### Responsible Use
+- ✅ Analyze your own accounts
+- ✅ Authorized competitor research
+- ✅ Permission-based security audits
+- ❌ Don't scrape private accounts
+- ❌ No harassment or stalking
+- ❌ Don't violate ToS
+
+---
+
+## 🆘 Troubleshooting
+
+### Login Issues
+- Check username/password
+- Try `--no-session` flag
+- Verify 2FA code if required
+
+### Profile Not Found
+- Verify username spelling
+- Check if account deleted
+- Private accounts have limited data
+
+### Database Errors
+- Close other instances
+- Delete `osint_data.db` to reset
+
+### Rate Limiting
+- Wait 30-60 minutes
+- Reduce batch sizes
+- Use `--limit-followers` option
+
+---
+
+## 🤝 Contributing
+
+Contributions welcome! Please:
+1. Fork the repository
+2. Create feature branch
+3. Make improvements
+4. Submit pull request
+
+### Ideas for Contribution
+- Additional export formats (XML, PDF)
+- Advanced analytics and predictions
+- Web UI dashboard
+- Performance improvements
+- Bug fixes
+
+---
+
+## 📝 Changelog
+
+### v2.0.0 (Current - December 2025)
+**Major Rewrite**
+- ✨ Complete modular refactoring (6 specialized modules)
+- ✨ Advanced CLI argument parsing
+- ✨ Batch processing with file input
+- ✨ SQLite database backend
+- ✨ Multi-format exports (JSON, CSV, HTML)
+- ✨ Professional analytics engine
+- ✨ Enhanced terminal UI
+- ✨ Profile comparison and analysis
+- 🐛 Improved error handling
+- 🐛 Better rate limiting
+
+### v1.0.0 (Original)
+- Basic profile analysis
+- Follower/following retrieval
+- JSON export
+- Post downloading
+- 2FA support
+
+---
+
+## 📮 Support
+
+### Having Issues?
+1. Check [Troubleshooting](#-troubleshooting)
+2. Review GitHub issues
+3. Create new issue with details
+
+### Questions?
+See examples and documentation above.
-### Result insta-osint tool
+---
-
+## 📄 License
-
+Original author: **HUNX04**
+v2.0 modernization and features
-
+Respect original creator's terms.
+---
+## 📞 Contact
+**Original Author:** HUNX04
+**Repository:** [INSTA-OSINT](https://github.com/HunxByts/INSTA-OSINT)
+---
+## ⭐ Support
-### Feature INSTA-OSINT
+If useful, please:
+- ⭐ Star the repository
+- 🐛 Report bugs
+- 💡 Suggest features
+- 📤 Share with others
+- 🤝 Contribute code
-| Featur | Status |
-|:-----------:|:-------:|
-| Username | ✔️ |
-| UserFull | ✔️ |
-| TypeAccount | ✔️ |
-| TargPost | ✔️ |
-| Follwers | ✔️ |
-| Followings | ✔️ |
-| id | ✔️ |
-| Bio | ✔️ |
-| Url | ✔️ |
-| AccountPrv | ✔️ |
-| AccountBis | ✔️ |
-| ProfPic | ✔️ |
-| IGTV | ✔️ |
-| Higlights | ✔️ |
-| ShowFollwrs | ✔️ |
-| ShowFollwng | ✔️ |
+---
+**Made with ❤️ for the OSINT Community**
-
-:zap: Author :
-- HunxByts
-
+**Last Updated:** December 30, 2025
+**Version:** 2.0.0
+**Status:** Production Ready
diff --git a/analyzer.py b/analyzer.py
new file mode 100644
index 0000000..d27dc8b
--- /dev/null
+++ b/analyzer.py
@@ -0,0 +1,113 @@
+"""Analytics engine for Instagram profiles"""
+
+class ProfileAnalytics:
+ """Analyze Instagram profile metrics"""
+
+ def __init__(self, profile):
+ self.profile = profile
+
+ def get_engagement_rate(self):
+ """Calculate estimated engagement rate (followers / posts)"""
+ if self.profile.mediacount == 0:
+ return 0
+ return round(self.profile.followers / self.profile.mediacount, 2)
+
+ def get_follower_following_ratio(self):
+ """Calculate follower to following ratio"""
+ if self.profile.followees == 0:
+ return self.profile.followers
+ return round(self.profile.followers / self.profile.followees, 2)
+
+ def get_profile_risk_score(self):
+ """Calculate risk score (higher = more suspicious)
+ Based on: low engagement, many following, few followers, no posts"""
+ risk = 0
+
+ # High following, low followers = risky
+ if self.profile.followees > self.profile.followers * 2:
+ risk += 30
+
+ # No posts but many followers = suspicious
+ if self.profile.mediacount == 0 and self.profile.followers > 100:
+ risk += 25
+
+ # Low engagement
+ if self.profile.mediacount > 0:
+ engagement = self.get_engagement_rate()
+ if engagement < 1:
+ risk += 20
+
+ # Likely bot indicators
+ if self.profile.is_private == False and self.profile.is_business_account == False and self.profile.followers > 1000:
+ if self.profile.mediacount == 0:
+ risk += 25
+
+ return min(risk, 100)
+
+ def get_profile_type(self):
+ """Classify profile type"""
+ if self.profile.is_business_account:
+ return "Business Account"
+ if self.profile.is_private:
+ return "Private Account"
+ if self.profile.followers > 10000:
+ return "Influencer"
+ if self.profile.mediacount == 0:
+ return "Inactive/Potential Bot"
+ return "Regular Account"
+
+ def get_analytics_summary(self):
+ """Get complete analytics summary"""
+ return {
+ "engagement_rate": self.get_engagement_rate(),
+ "follower_ratio": self.get_follower_following_ratio(),
+ "risk_score": self.get_profile_risk_score(),
+ "profile_type": self.get_profile_type(),
+ "posts_per_follower": round(self.profile.mediacount / max(self.profile.followers, 1), 4),
+ "following_percentage": round((self.profile.followees / max(self.profile.followers, 1)) * 100, 2) if self.profile.followers > 0 else 0
+ }
+
+
+class ComparativeAnalytics:
+ """Compare multiple profiles"""
+
+ @staticmethod
+ def compare_profiles(profile_list):
+ """Compare multiple profiles and return insights"""
+ if not profile_list:
+ return {}
+
+ analytics_list = [ProfileAnalytics(p) for p in profile_list]
+
+ total_followers = sum(p.profile.followers for p in profile_list)
+ total_following = sum(p.profile.followees for p in profile_list)
+ total_posts = sum(p.profile.mediacount for p in profile_list)
+
+ return {
+ "profile_count": len(profile_list),
+ "total_followers": total_followers,
+ "total_following": total_following,
+ "total_posts": total_posts,
+ "avg_followers": round(total_followers / len(profile_list), 0),
+ "avg_following": round(total_following / len(profile_list), 0),
+ "avg_posts": round(total_posts / len(profile_list), 0),
+ "profiles": [a.get_analytics_summary() for a in analytics_list]
+ }
+
+ @staticmethod
+ def find_mutual_followers(followers_list1, followers_list2):
+ """Find mutual followers between two follower lists"""
+ usernames1 = {f["username"] for f in followers_list1}
+ usernames2 = {f["username"] for f in followers_list2}
+
+ mutual = usernames1.intersection(usernames2)
+
+ # Reconstruct mutual follower objects
+ mutual_followers = [f for f in followers_list1 if f["username"] in mutual]
+
+ return {
+ "mutual_count": len(mutual),
+ "mutual_followers": mutual_followers,
+ "percentage_of_first": round((len(mutual) / len(followers_list1)) * 100, 2) if followers_list1 else 0,
+ "percentage_of_second": round((len(mutual) / len(followers_list2)) * 100, 2) if followers_list2 else 0
+ }
diff --git a/cli.py b/cli.py
new file mode 100644
index 0000000..e3e6c71
--- /dev/null
+++ b/cli.py
@@ -0,0 +1,82 @@
+"""CLI argument parser and configuration"""
+
+import argparse
+
+def get_args():
+ """Parse command line arguments"""
+ parser = argparse.ArgumentParser(
+ description='Instagram OSINT Tool - Gather intelligence on Instagram profiles',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="""
+Examples:
+ # Interactive mode
+ python instaOSINT.py
+
+ # Specify account and target
+ python instaOSINT.py -u myusername -p mypassword -t targetusername
+
+ # Batch mode with multiple targets
+ python instaOSINT.py -u myusername -p mypassword -f targets.txt
+
+ # Export to specific format
+ python instaOSINT.py -u myusername -p mypassword -t targetusername -o html,json,csv
+
+ # Store data in database and analyze
+ python instaOSINT.py -u myusername -p mypassword -t targetusername --db --analyze
+ """
+ )
+
+ # Authentication arguments
+ auth_group = parser.add_argument_group('Authentication')
+ auth_group.add_argument('-u', '--username', help='Instagram username')
+ auth_group.add_argument('-p', '--password', help='Instagram password')
+ auth_group.add_argument('--no-session', action='store_true', help='Do not use saved session')
+
+ # Target arguments
+ target_group = parser.add_argument_group('Target')
+ target_group.add_argument('-t', '--target', help='Single target username')
+ target_group.add_argument('-f', '--file', help='File with list of target usernames (one per line)')
+
+ # Output arguments
+ output_group = parser.add_argument_group('Output')
+ output_group.add_argument('-o', '--output', default='json',
+ help='Export format(s): json, csv, html (comma-separated, default: json)')
+ output_group.add_argument('-d', '--dir', default='.', help='Output directory (default: current)')
+
+ # Feature arguments
+ feature_group = parser.add_argument_group('Features')
+ feature_group.add_argument('--db', action='store_true', help='Store data in database')
+ feature_group.add_argument('--analyze', action='store_true', help='Run analytics and calculate metrics')
+ feature_group.add_argument('--compare', action='store_true', help='Compare multiple profiles')
+ feature_group.add_argument('--no-download', action='store_true', help='Skip downloading posts/highlights')
+
+ # Performance arguments
+ perf_group = parser.add_argument_group('Performance')
+ perf_group.add_argument('--limit-followers', type=int, help='Limit followers to fetch (default: all)')
+ perf_group.add_argument('--limit-following', type=int, help='Limit following to fetch (default: all)')
+ perf_group.add_argument('--quiet', action='store_true', help='Minimize console output')
+
+ return parser.parse_args()
+
+def validate_args(args):
+ """Validate parsed arguments"""
+ errors = []
+
+ if not args.target and not args.file:
+ errors.append("Either --target or --file must be specified")
+
+ if args.target and args.file:
+ errors.append("Cannot specify both --target and --file")
+
+ valid_formats = ['json', 'csv', 'html']
+ formats = [f.strip().lower() for f in args.output.split(',')]
+ invalid = [f for f in formats if f not in valid_formats]
+ if invalid:
+ errors.append(f"Invalid output format(s): {', '.join(invalid)}")
+
+ if errors:
+ for error in errors:
+ print(f"Error: {error}")
+ return False
+
+ return True
diff --git a/database.py b/database.py
new file mode 100644
index 0000000..8347c75
--- /dev/null
+++ b/database.py
@@ -0,0 +1,239 @@
+"""Database management for Instagram OSINT"""
+
+import sqlite3
+from datetime import datetime
+import json
+
+class OsintDatabase:
+ """SQLite database for storing OSINT data"""
+
+ def __init__(self, db_name="osint_data.db"):
+ self.db_name = db_name
+ self.init_database()
+
+ def init_database(self):
+ """Initialize database with required tables"""
+ conn = sqlite3.connect(self.db_name)
+ cursor = conn.cursor()
+
+ # Profiles table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS profiles (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT UNIQUE,
+ user_id INTEGER,
+ full_name TEXT,
+ biography TEXT,
+ external_url TEXT,
+ is_private BOOLEAN,
+ is_business BOOLEAN,
+ business_category TEXT,
+ followers INTEGER,
+ following INTEGER,
+ posts INTEGER,
+ profile_pic_url TEXT,
+ first_seen TIMESTAMP,
+ last_updated TIMESTAMP
+ )
+ ''')
+
+ # Followers table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS followers (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ profile_username TEXT,
+ follower_username TEXT,
+ follower_id INTEGER,
+ follower_full_name TEXT,
+ recorded_at TIMESTAMP,
+ FOREIGN KEY(profile_username) REFERENCES profiles(username)
+ )
+ ''')
+
+ # Historical data table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS profile_history (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT,
+ followers_count INTEGER,
+ following_count INTEGER,
+ posts_count INTEGER,
+ recorded_at TIMESTAMP,
+ FOREIGN KEY(username) REFERENCES profiles(username)
+ )
+ ''')
+
+ # Analytics cache table
+ cursor.execute('''
+ CREATE TABLE IF NOT EXISTS analytics_cache (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT,
+ engagement_rate REAL,
+ follower_ratio REAL,
+ risk_score INTEGER,
+ profile_type TEXT,
+ recorded_at TIMESTAMP,
+ FOREIGN KEY(username) REFERENCES profiles(username)
+ )
+ ''')
+
+ conn.commit()
+ conn.close()
+
+ def save_profile(self, profile):
+ """Save profile data to database"""
+ conn = sqlite3.connect(self.db_name)
+ cursor = conn.cursor()
+
+ try:
+ cursor.execute('''
+ INSERT OR REPLACE INTO profiles
+ (username, user_id, full_name, biography, external_url, is_private, is_business,
+ business_category, followers, following, posts, profile_pic_url, last_updated)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ''', (
+ profile.username,
+ profile.userid,
+ profile.full_name,
+ profile.biography,
+ profile.external_url,
+ profile.is_private,
+ profile.is_business_account,
+ profile.business_category_name,
+ profile.followers,
+ profile.followees,
+ profile.mediacount,
+ profile.profile_pic_url,
+ datetime.now()
+ ))
+
+ # Also record in history
+ cursor.execute('''
+ INSERT INTO profile_history
+ (username, followers_count, following_count, posts_count, recorded_at)
+ VALUES (?, ?, ?, ?, ?)
+ ''', (
+ profile.username,
+ profile.followers,
+ profile.followees,
+ profile.mediacount,
+ datetime.now()
+ ))
+
+ conn.commit()
+ return True
+ except Exception as e:
+ print(f"Error saving profile: {e}")
+ return False
+ finally:
+ conn.close()
+
+ def save_followers(self, profile_username, followers_list):
+ """Save followers to database"""
+ conn = sqlite3.connect(self.db_name)
+ cursor = conn.cursor()
+
+ try:
+ for follower in followers_list:
+ cursor.execute('''
+ INSERT INTO followers
+ (profile_username, follower_username, follower_id, follower_full_name, recorded_at)
+ VALUES (?, ?, ?, ?, ?)
+ ''', (
+ profile_username,
+ follower.get("username"),
+ follower.get("user_id"),
+ follower.get("full_name"),
+ datetime.now()
+ ))
+
+ conn.commit()
+ return True
+ except Exception as e:
+ print(f"Error saving followers: {e}")
+ return False
+ finally:
+ conn.close()
+
+ def save_analytics(self, username, analytics_data):
+ """Save analytics results"""
+ conn = sqlite3.connect(self.db_name)
+ cursor = conn.cursor()
+
+ try:
+ cursor.execute('''
+ INSERT INTO analytics_cache
+ (username, engagement_rate, follower_ratio, risk_score, profile_type, recorded_at)
+ VALUES (?, ?, ?, ?, ?, ?)
+ ''', (
+ username,
+ analytics_data.get("engagement_rate"),
+ analytics_data.get("follower_ratio"),
+ analytics_data.get("risk_score"),
+ analytics_data.get("profile_type"),
+ datetime.now()
+ ))
+
+ conn.commit()
+ return True
+ except Exception as e:
+ print(f"Error saving analytics: {e}")
+ return False
+ finally:
+ conn.close()
+
+ def get_profile_history(self, username):
+ """Get historical data for a profile"""
+ conn = sqlite3.connect(self.db_name)
+ cursor = conn.cursor()
+
+ try:
+ cursor.execute('''
+ SELECT followers_count, following_count, posts_count, recorded_at
+ FROM profile_history
+ WHERE username = ?
+ ORDER BY recorded_at
+ ''', (username,))
+
+ results = cursor.fetchall()
+ return [
+ {
+ "followers": r[0],
+ "following": r[1],
+ "posts": r[2],
+ "recorded_at": r[3]
+ }
+ for r in results
+ ]
+ finally:
+ conn.close()
+
+ def get_growth_stats(self, username):
+ """Calculate growth stats from history"""
+ history = self.get_profile_history(username)
+
+ if len(history) < 2:
+ return None
+
+ first = history[0]
+ last = history[-1]
+
+ return {
+ "followers_change": last["followers"] - first["followers"],
+ "following_change": last["following"] - first["following"],
+ "posts_change": last["posts"] - first["posts"],
+ "data_points": len(history),
+ "first_recorded": first["recorded_at"],
+ "last_recorded": last["recorded_at"]
+ }
+
+ def get_all_profiles(self):
+ """Get all stored profiles"""
+ conn = sqlite3.connect(self.db_name)
+ cursor = conn.cursor()
+
+ try:
+ cursor.execute('SELECT username FROM profiles')
+ return [row[0] for row in cursor.fetchall()]
+ finally:
+ conn.close()
diff --git a/exporter.py b/exporter.py
new file mode 100644
index 0000000..e728781
--- /dev/null
+++ b/exporter.py
@@ -0,0 +1,244 @@
+"""Export functionality for multiple formats"""
+
+import json
+import csv
+from datetime import datetime
+from utils import Gr, Re, Wh, Ye
+
+class Exporter:
+ """Handle exports in multiple formats"""
+
+ @staticmethod
+ def export_json(profile, followers_list, followees_list, username, analytics=None):
+ """Export to JSON format"""
+ data = {
+ "export_date": datetime.now().isoformat(),
+ "profile": {
+ "username": profile.username,
+ "full_name": profile.full_name,
+ "user_id": profile.userid,
+ "biography": profile.biography,
+ "external_url": profile.external_url,
+ "is_private": profile.is_private,
+ "is_business_account": profile.is_business_account,
+ "business_category": profile.business_category_name,
+ "followers_count": profile.followers,
+ "following_count": profile.followees,
+ "posts_count": profile.mediacount,
+ "profile_pic_url": profile.profile_pic_url
+ },
+ "followers": followers_list,
+ "following": followees_list
+ }
+
+ if analytics:
+ data["analytics"] = analytics
+
+ filename = f"{username}_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
+ with open(filename, 'w', encoding='utf-8') as f:
+ json.dump(data, f, indent=2, ensure_ascii=False)
+
+ return filename
+
+ @staticmethod
+ def export_csv(profile, followers_list, followees_list, username):
+ """Export to CSV format"""
+ timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
+
+ # Profile CSV
+ profile_file = f"{username}_profile_{timestamp}.csv"
+ with open(profile_file, 'w', newline='', encoding='utf-8') as f:
+ writer = csv.writer(f)
+ writer.writerow(['Metric', 'Value'])
+ writer.writerow(['Username', profile.username])
+ writer.writerow(['Full Name', profile.full_name])
+ writer.writerow(['User ID', profile.userid])
+ writer.writerow(['Biography', profile.biography])
+ writer.writerow(['External URL', profile.external_url])
+ writer.writerow(['Is Private', profile.is_private])
+ writer.writerow(['Is Business', profile.is_business_account])
+ writer.writerow(['Followers', profile.followers])
+ writer.writerow(['Following', profile.followees])
+ writer.writerow(['Posts', profile.mediacount])
+
+ # Followers CSV
+ followers_file = f"{username}_followers_{timestamp}.csv"
+ with open(followers_file, 'w', newline='', encoding='utf-8') as f:
+ writer = csv.DictWriter(f, fieldnames=['username', 'user_id', 'full_name'])
+ writer.writeheader()
+ writer.writerows(followers_list)
+
+ # Following CSV
+ following_file = f"{username}_following_{timestamp}.csv"
+ with open(following_file, 'w', newline='', encoding='utf-8') as f:
+ writer = csv.DictWriter(f, fieldnames=['username', 'user_id', 'full_name'])
+ writer.writeheader()
+ writer.writerows(followees_list)
+
+ return profile_file, followers_file, following_file
+
+ @staticmethod
+ def export_html(profile, followers_list, followees_list, username, analytics=None):
+ """Export to HTML report format"""
+ timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
+ filename = f"{username}_report_{timestamp}.html"
+
+ html_content = f"""
+
+
+
+ Instagram OSINT Report - {username}
+
+
+
+
+
📊 Instagram OSINT Report
+
+
Profile Information
+
+
+ Username: {profile.username}
+
+
+ User ID: {profile.userid}
+
+
+ Full Name: {profile.full_name}
+
+
+ Followers: {profile.followers:,}
+
+
+ Following: {profile.followees:,}
+
+
+ Posts: {profile.mediacount}
+
+
+ Private: {"Yes" if profile.is_private else "No"}
+
+
+ Business Account: {"Yes" if profile.is_business_account else "No"}
+
+
+
+
+
+ Biography:
{profile.biography or "N/A"}
+
+
+ External URL:
{profile.external_url or "N/A"}
+
+
+ """
+
+ if analytics:
+ html_content += f"""
+
+
📈 Analytics
+
+
+ Engagement Rate: {analytics.get('engagement_rate', 'N/A')}
+
+
+ Follower Ratio: {analytics.get('follower_ratio', 'N/A')}
+
+
+ Profile Type: {analytics.get('profile_type', 'N/A')}
+
+
+ Risk Score: {analytics.get('risk_score', 'N/A')}/100
+
+
+
+ """
+
+ html_content += f"""
+
Followers ({len(followers_list)})
+
+
+
+ | Username |
+ User ID |
+ Full Name |
+
+
+
+ """
+
+ for follower in followers_list[:100]: # Limit to first 100 for performance
+ html_content += f"""
+
+ | {follower.get('username', 'N/A')} |
+ {follower.get('user_id', 'N/A')} |
+ {follower.get('full_name', 'N/A')} |
+
+ """
+
+ if len(followers_list) > 100:
+ html_content += f"""
+
+ | ... and {len(followers_list) - 100} more followers |
+
+ """
+
+ html_content += f"""
+
+
+
+
Following ({len(followees_list)})
+
+
+
+ | Username |
+ User ID |
+ Full Name |
+
+
+
+ """
+
+ for followee in followees_list[:100]:
+ html_content += f"""
+
+ | {followee.get('username', 'N/A')} |
+ {followee.get('user_id', 'N/A')} |
+ {followee.get('full_name', 'N/A')} |
+
+ """
+
+ if len(followees_list) > 100:
+ html_content += f"""
+
+ | ... and {len(followees_list) - 100} more following |
+
+ """
+
+ html_content += f"""
+
+
+
+
Report generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
+
+
+
+ """
+
+ with open(filename, 'w', encoding='utf-8') as f:
+ f.write(html_content)
+
+ return filename
diff --git a/instaOSINT.py b/instaOSINT.py
index 6760e16..a0c8043 100644
--- a/instaOSINT.py
+++ b/instaOSINT.py
@@ -2,127 +2,358 @@
# << CODE BY HUNX04
# << MAU RECODE ??? IZIN DULU LAH , MINIMAL TAG AKUN GITHUB MIMIN YANG MENGARAH KE AKUN INI, LEBIH ENAKNYA SIH FORK
# << KALAU DI ATAS TIDAK DI IKUTI MAKA AKAN MENDAPATKAN DOSA KARENA MIMIN GAK IKHLAS DUNIA AKHIRAT SAMPAI 7 TURUNAN
-# “Wahai orang-orang yang beriman! Janganlah kamu saling memakan harta sesamamu dengan jalan yang batil,” (QS. An Nisaa': 29). Rasulullah SAW juga melarang umatnya untuk mengambil hak orang lain tanpa izin.
+# "Wahai orang-orang yang beriman! Janganlah kamu saling memakan harta sesamamu dengan jalan yang batil," (QS. An Nisaa': 29). Rasulullah SAW juga melarang umatnya untuk mengambil hak orang lain tanpa izin.
-import instaloader #MUDULE
-import time
-from sys import stderr
import sys
import os
+import time
+import getpass
+from cli import get_args, validate_args
+from processor import InstagramOSINT
+from utils import print_logo, print_info, print_warning, print_error, print_success, print_header, Wh, Gr, Ye, Cy
+from menu import (display_main_menu, get_menu_choice, display_features_menu,
+ get_features_config, display_export_menu, get_export_format,
+ get_target_input, get_multiple_targets, get_limit_options,
+ confirm_action, display_summary)
+from database import OsintDatabase
+def interactive_mode():
+ """Interactive CLI mode with menu system"""
+ print_logo()
+ print_header("AUTHENTICATION")
+
+ # Get credentials
+ username = input(f"\n {Wh}[{Gr}>{Wh}] {Cy}Instagram username: {Ye}")
+ password = getpass.getpass(f" {Wh}[{Gr}>{Wh}] {Cy}Instagram password: {Ye}")
+
+ os.system('clear')
+ print_logo()
+
+ # Initialize OSINT processor
+ osint = InstagramOSINT(username, password)
+
+ # Authenticate
+ print_info("Authenticating...")
+ if not osint.authenticate():
+ print_error("Authentication failed!")
+ sys.exit(1)
+
+ print_success("Authentication successful!")
+ time.sleep(1)
+
+ # Main menu loop
+ while True:
+ os.system('clear')
+ print_logo()
+ display_main_menu()
+
+ choice = get_menu_choice("Select an option", ['1', '2', '3', '4', '5'])
+
+ if choice == '5':
+ print_success("Goodbye!")
+ sys.exit(0)
+
+ elif choice == '1':
+ # Single profile analysis
+ handle_single_profile(osint)
+
+ elif choice == '2':
+ # Batch analysis
+ handle_batch_profiles(osint)
+
+ elif choice == '3':
+ # Compare profiles
+ handle_compare_profiles(osint)
+
+ elif choice == '4':
+ # View database
+ handle_view_database()
+
+ # Ask if user wants to continue
+ if not confirm_action("Continue with another operation?"):
+ print_success("Goodbye!")
+ sys.exit(0)
+def handle_single_profile(osint):
+ """Handle single profile analysis"""
+ os.system('clear')
+ print_logo()
+
+ # Get target
+ target = get_target_input()
+
+ # Get features configuration
+ features_config = get_features_config()
+
+ # Get export format
+ export_format = get_export_format()
+
+ # Get limits
+ follower_limit, following_limit = get_limit_options()
+
+ # Build options
+ options = {
+ 'analyze': features_config['analyze'],
+ 'db': features_config['db'],
+ 'no_download': features_config['no_download'],
+ 'limit_followers': follower_limit,
+ 'limit_following': following_limit
+ }
+
+ # Show summary
+ config_summary = {**options, 'export_format': export_format, 'download': features_config['download']}
+ display_summary(config_summary)
+
+ if not confirm_action("Proceed with analysis?"):
+ print_warning("Analysis cancelled")
+ return
+
+ # Process
+ print_header("PROCESSING")
+ print_info(f"Analyzing profile: {target}")
+
+ results = osint.process_profile(target, options)
+
+ if results:
+ # Export results
+ print_info("Exporting results...")
+ exported = osint.export_results(results, target, export_format)
+ print_success(f"✓ Exported {len(exported)} file(s)")
+ for file in exported:
+ print(f" {Wh}• {Gr}{file}")
+ else:
+ print_error("Failed to process target")
-Bl='\033[30m' # VARIABLE COLOR
-Re='\033[1;31m'
-Gr='\033[1;32m'
-Ye='\033[1;33m'
-Blu='\033[1;34m'
-Mage='\033[1;35m'
-Cy='\033[1;36m'
-Wh='\033[1;37m'
-
-
-try:
-#LOGO GW
- stderr.writelines(f"""{Gr}
-
- {Gr}██╗███╗ ██╗███████╗████████╗ █████╗ {Re}██████╗ ███████╗██╗███╗ ██╗████████╗
- {Gr}██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗ {Re}██╔═══██╗██╔════╝██║████╗ ██║╚══██╔══╝
- {Gr}██║██╔██╗ ██║███████╗ ██║ ███████║{Wh}█████╗{Re}██║ ██║███████╗██║██╔██╗ ██║ ██║
- {Gr}██║██║╚██╗██║╚════██║ ██║ ██╔══██║{Wh}╚════╝{Re}██║ ██║╚════██║██║██║╚██╗██║ ██║
- {Gr}██║██║ ╚████║███████║ ██║ ██║ ██║ {Re}╚██████╔╝███████║██║██║ ╚████║ ██║
- {Gr}╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ {Re}╚═════╝ ╚══════╝╚═╝╚═╝ ╚═══╝ ╚═╝
- {Wh} <----- {Gr}O S I N T {Wh}I N S T A G R A M {Wh}B Y {Gr}H U N B Y T S {Wh}----->
- """)
- print(f"\n {Wh}[ {Gr}! {Wh}] LOGIN YOUR INSTAGRAM ACCOUNT")
- US = input(f"\n [ {Gr}+ {Wh}] INPUT USERNAME INSTAGRAM ACCOUNT : {Re}")
- PW = input(f" {Wh}[ {Gr}+ {Wh}] INPUT PASSWORD INSTAGRAM ACCOUNT : {Re}")
+def handle_batch_profiles(osint):
+ """Handle batch profile analysis"""
+ os.system('clear')
+ print_logo()
+
+ # Get targets
+ targets = get_multiple_targets()
+
+ if not targets:
+ print_warning("No targets provided")
+ return
+
+ print_info(f"Total targets: {len(targets)}")
+
+ # Get features configuration
+ features_config = get_features_config()
+
+ # Get export format
+ export_format = get_export_format()
+
+ # Get limits
+ follower_limit, following_limit = get_limit_options()
+
+ # Build options
+ options = {
+ 'analyze': features_config['analyze'],
+ 'db': features_config['db'],
+ 'no_download': features_config['no_download'],
+ 'limit_followers': follower_limit,
+ 'limit_following': following_limit
+ }
+
+ # Show summary
+ config_summary = {**options, 'export_format': export_format, 'download': features_config['download']}
+ display_summary(config_summary)
+
+ if not confirm_action(f"Proceed with {len(targets)} profiles?"):
+ print_warning("Analysis cancelled")
+ return
+
+ # Process batch
+ print_header("BATCH PROCESSING")
+
+ for idx, target in enumerate(targets, 1):
+ print_info(f"Processing [{idx}/{len(targets)}]: {target}")
+
+ results = osint.process_profile(target, options)
+
+ if results:
+ exported = osint.export_results(results, target, export_format)
+ print_success(f"✓ Completed {target}")
+ else:
+ print_error(f"✗ Failed {target}")
+
+ if idx < len(targets):
+ time.sleep(2) # Rate limiting
+
+ print_success(f"✓ Batch processing complete! Processed {len(targets)} profiles")
+def handle_compare_profiles(osint):
+ """Handle profile comparison"""
os.system('clear')
+ print_logo()
+
+ print_info("Profile comparison requires at least 2 profiles")
+ targets = get_multiple_targets()
+
+ if len(targets) < 2:
+ print_warning("Need at least 2 profiles to compare")
+ return
+
+ print_info(f"Comparing {len(targets)} profiles")
+
+ # Get options
+ options = {
+ 'analyze': True,
+ 'db': True,
+ 'no_download': True,
+ 'limit_followers': 100, # Limit for comparison
+ 'limit_following': 100
+ }
+
+ if not confirm_action(f"Compare {len(targets)} profiles?"):
+ print_warning("Comparison cancelled")
+ return
+
+ # Process all profiles
+ print_header("COMPARING PROFILES")
+ all_results = []
+
+ for idx, target in enumerate(targets, 1):
+ print_info(f"Fetching [{idx}/{len(targets)}]: {target}")
+ results = osint.process_profile(target, options)
+ if results:
+ all_results.append(results)
+
+ if len(all_results) >= 2:
+ print_header("COMPARISON RESULTS")
+
+ # Display comparison
+ for result in all_results:
+ profile = result['profile']
+ analytics = result.get('analytics', {})
+
+ print(f"\n {Cy}Profile: {Gr}{profile.username}")
+ print(f" {Wh}├─ Followers: {Ye}{profile.followers:,}")
+ print(f" {Wh}├─ Following: {Ye}{profile.followees:,}")
+ print(f" {Wh}├─ Posts: {Ye}{profile.mediacount}")
+
+ if analytics:
+ print(f" {Wh}├─ Engagement Rate: {Ye}{analytics.get('engagement_rate', 0)}")
+ print(f" {Wh}├─ Follower Ratio: {Ye}{analytics.get('follower_ratio', 0)}")
+ print(f" {Wh}└─ Risk Score: {Ye}{analytics.get('risk_score', 0)}/100")
+
+ print_success(f"\n✓ Comparison complete!")
+ else:
+ print_error("Failed to fetch enough profiles for comparison")
- def osintig(US,PW):
- stderr.writelines(f"""{Gr}
+def handle_view_database():
+ """View database statistics"""
+ os.system('clear')
+ print_logo()
+ print_header("DATABASE VIEWER")
+
+ db = OsintDatabase()
+ profiles = db.get_all_profiles()
+
+ if not profiles:
+ print_warning("No profiles in database yet")
+ return
+
+ print_info(f"Total profiles stored: {len(profiles)}")
+ print()
+
+ for profile in profiles[:10]: # Show first 10
+ print(f" {Wh}• {Gr}{profile}")
+
+ # Try to get history
+ history = db.get_profile_history(profile)
+ if len(history) > 1:
+ growth = db.get_growth_stats(profile)
+ if growth:
+ print(f" {Wh}├─ Data points: {Ye}{growth['data_points']}")
+ print(f" {Wh}├─ Follower change: {Ye}{growth['followers_change']:+,}")
+ print(f" {Wh}└─ Following change: {Ye}{growth['following_change']:+,}")
+
+ if len(profiles) > 10:
+ print(f"\n {Wh}... and {Ye}{len(profiles) - 10}{Wh} more profiles")
+
+ print()
- {Gr}██╗███╗ ██╗███████╗████████╗ █████╗ {Re}██████╗ ███████╗██╗███╗ ██╗████████╗
- {Gr}██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗ {Re}██╔═══██╗██╔════╝██║████╗ ██║╚══██╔══╝
- {Gr}██║██╔██╗ ██║███████╗ ██║ ███████║{Wh}█████╗{Re}██║ ██║███████╗██║██╔██╗ ██║ ██║
- {Gr}██║██║╚██╗██║╚════██║ ██║ ██╔══██║{Wh}╚════╝{Re}██║ ██║╚════██║██║██║╚██╗██║ ██║
- {Gr}██║██║ ╚████║███████║ ██║ ██║ ██║ {Re}╚██████╔╝███████║██║██║ ╚████║ ██║
- {Gr}╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ {Re}╚═════╝ ╚══════╝╚═╝╚═╝ ╚═══╝ ╚═╝
- {Wh} <----- {Gr}O S I N T {Wh}I N S T A G R A M {Wh}B Y {Gr}H U N B Y T S {Wh}----->
- """)
- IG_INSTA = instaloader.Instaloader()
- IG_INSTA.login(US, PW)
- if not IG_INSTA.context.is_logged_in:
- IG_INSTA.context.log(f"\n {Wh}[ {Gr}+ {Wh}] {Re}Login failed!, you account wrong")
- else:
- IG_INSTA.context.log(f"\n {Wh}[ {Gr}+ {Wh}] {Gr}Login Success!")
- time.sleep(3)
- user_input = input(f"\n {Wh}[ {Gr}+ {Wh}] INPUT USERNAME TARGET : {Re}")
- profile = instaloader.Profile.from_username(IG_INSTA.context, user_input)
+def cli_mode(args):
+ """Command-line argument mode"""
+ # Prepare options
+ options = {
+ 'analyze': args.analyze,
+ 'db': args.db,
+ 'no_download': args.no_download,
+ 'limit_followers': args.limit_followers,
+ 'limit_following': args.limit_following
+ }
+
+ # Initialize OSINT processor
+ osint = InstagramOSINT(
+ args.username,
+ args.password,
+ use_session=not args.no_session,
+ quiet=args.quiet
+ )
+
+ # Authenticate
+ if not osint.authenticate():
+ if not args.quiet:
+ print_error("Authentication failed!")
+ sys.exit(1)
+
+ # Get target list
+ targets = []
+ if args.target:
+ targets = [args.target]
+ elif args.file:
+ try:
+ with open(args.file, 'r') as f:
+ targets = [line.strip() for line in f if line.strip()]
+ except FileNotFoundError:
+ if not args.quiet:
+ print_error(f"File not found: {args.file}")
+ sys.exit(1)
+
+ # Process targets
+ if args.compare and len(targets) > 1:
+ # Comparison mode
+ all_results = osint.batch_process(targets, options)
+
+ if all_results:
+ # Export each profile
+ for result in all_results:
+ profile = result['profile']
+ osint.export_results(result, profile.username, args.output)
+ else:
+ # Single or batch mode
+ for target in targets:
+ result = osint.process_profile(target, options)
+ if result:
+ osint.export_results(result, target, args.output)
+ time.sleep(2) # Rate limiting
- print(f"\n {Wh}============================== {Gr}INFORMATION ACCOUNT {Wh}=============================")
- print(f"\n {Wh}Username :{Gr} {profile.username}")
- print(f" {Wh}Full Name :{Gr} {profile.full_name}")
- print(f" {Wh}Id :{Gr} {profile.userid}")
- print(f" {Wh}Bio :{Gr} {profile.biography}")
- print(f" {Wh}Url Profile :{Gr} {profile.external_url}")
- print(f" {Wh}Account Private :{Gr} {profile.is_private}")
- print(f" {Wh}Account Business :{Gr} {profile.is_business_account}")
- print(f" {Wh}Account business type :{Gr} {profile.business_category_name}")
- print(f" {Wh}Followers :{Gr} {profile.followers}")
- print(f" {Wh}Following :{Gr} {profile.followees}")
- print(f" {Wh}Total Post :{Gr} {profile.mediacount}")
- time.sleep(0.3)
- print(f"\n {Wh}[ {Gr}+ {Wh}]{Wh} Download profile picture : ")
- profile_pic = profile.profile_pic_url
- print(profile_pic)
- print()
- print(f" {Wh}[ {Gr}+ {Wh}]{Wh} Download {Gr}target post : ")
- for post in profile.get_posts():
- IG_INSTA.download_post(post, target=profile.username)
- print()
- print(f" {Wh}[ {Gr}+ {Wh}]{Wh} Download {Gr}igtv post : ")
- for post in IG_INSTA.get_feed_posts():
- IG_INSTA.download_post(post, target=profile.username)
- print()
- print(f" {Wh}[ {Gr}+ {Wh}]{Wh} Download {Gr}highlights post : ")
- for highlight in IG_INSTA.get_highlights(profile):
- for post in highlight.get_items():
- IG_INSTA.download_storyitem(post, target=profile.username)
- print()
- def animasi():
- for i in range(10):
- sys.stdout.write(f'\r {Wh}LOADING {Gr}|')
- time.sleep(0.1)
- sys.stdout.write(f'\r {Wh}LOADING {Gr}/')
- time.sleep(0.1)
- sys.stdout.write(f'\r {Wh}LOADING {Gr}-')
- time.sleep(0.1)
- sys.stdout.write(f'\r {Wh}LOADING {Gr}\\')
- animasi()
- print(f"\n {Wh}[ {Gr}+ {Wh}]{Wh} Show {Gr}target followers : ")
- followers = profile.get_followers()
- for follower in followers:
- print(f" {Gr}USERNAME : {Wh}{follower.username} {Gr}| ID : {Wh}{follower.userid}")
+def main():
+ """Main entry point"""
+ try:
+ # Check if arguments provided
+ if len(sys.argv) > 1:
+ args = get_args()
+
+ if not validate_args(args):
+ sys.exit(1)
+
+ cli_mode(args)
+ else:
+ interactive_mode()
+
+ except KeyboardInterrupt:
+ print(f"\n[!] Program interrupted by user")
+ sys.exit(0)
+ except Exception as e:
+ print_error(f"Unexpected error: {str(e)}")
+ sys.exit(1)
- def animasi():
- for i in range(10):
- sys.stdout.write(f'\r {Wh}LOADING {Gr}|')
- time.sleep(0.1)
- sys.stdout.write(f'\r {Wh}LOADING {Gr}/')
- time.sleep(0.1)
- sys.stdout.write(f'\r {Wh}LOADING {Gr}-')
- time.sleep(0.1)
- sys.stdout.write(f'\r {Wh}LOADING {Gr}\\')
- animasi()
- print(f"\n {Wh}[ {Gr}+ {Wh}]{Wh} Show {Gr}target followings : ")
- followees = profile.get_followees()
- for followee in followees:
- print(f" {Gr}USERNAME : {Wh}{followee.username} {Gr}| ID : {Wh}{followee.userid}")
- osintig(US,PW)
-except KeyboardInterrupt:
- print(f" {Wh}[ {Ye}! {Wh}] {Ye}PROGRAM STOPPED...")
+if __name__ == "__main__":
+ main()
diff --git a/menu.py b/menu.py
new file mode 100644
index 0000000..bbea242
--- /dev/null
+++ b/menu.py
@@ -0,0 +1,167 @@
+"""Interactive menu system for Instagram OSINT"""
+
+from utils import print_header, print_info, print_success, print_error, print_warning, Wh, Gr, Ye, Cy, Re
+
+def display_main_menu():
+ """Display main menu options"""
+ print_header("MAIN MENU")
+ print(f"""
+ {Wh}[{Gr}1{Wh}] {Cy}Single Profile Analysis
+ {Wh}[{Gr}2{Wh}] {Cy}Batch Profile Analysis (Multiple Targets)
+ {Wh}[{Gr}3{Wh}] {Cy}Compare Profiles
+ {Wh}[{Gr}4{Wh}] {Cy}View Database History
+ {Wh}[{Gr}5{Wh}] {Re}Exit
+ """)
+
+def get_menu_choice(prompt, valid_choices):
+ """Get user menu choice with validation"""
+ while True:
+ choice = input(f"\n {Wh}[{Gr}?{Wh}] {prompt}: {Ye}").strip()
+ if choice in valid_choices:
+ return choice
+ print_error(f"Invalid choice. Please select from {', '.join(valid_choices)}")
+
+def display_features_menu():
+ """Display features configuration menu"""
+ print_header("FEATURES CONFIGURATION")
+ print(f"""
+ {Wh}Select features to enable:
+
+ {Wh}[{Gr}1{Wh}] {Cy}Download Posts & Highlights {Ye}(may take time)
+ {Wh}[{Gr}2{Wh}] {Cy}Run Analytics {Ye}(engagement, risk scoring)
+ {Wh}[{Gr}3{Wh}] {Cy}Save to Database {Ye}(historical tracking)
+ {Wh}[{Gr}4{Wh}] {Cy}All Features
+ {Wh}[{Gr}5{Wh}] {Cy}None (Quick mode - basic info only)
+ """)
+
+def get_features_config():
+ """Get features configuration from user"""
+ display_features_menu() # Show the menu before asking
+ choice = get_menu_choice("Choose features option", ['1', '2', '3', '4', '5'])
+
+ config = {
+ 'download': False,
+ 'analyze': False,
+ 'db': False,
+ 'no_download': True
+ }
+
+ if choice == '1':
+ config['download'] = True
+ config['no_download'] = False
+ elif choice == '2':
+ config['analyze'] = True
+ elif choice == '3':
+ config['db'] = True
+ elif choice == '4':
+ config['download'] = True
+ config['analyze'] = True
+ config['db'] = True
+ config['no_download'] = False
+ # Choice 5 keeps defaults (quick mode)
+
+ return config
+
+def display_export_menu():
+ """Display export format menu"""
+ print_header("EXPORT FORMATS")
+ print(f"""
+ {Wh}Select export format(s):
+
+ {Wh}[{Gr}1{Wh}] {Cy}JSON only {Ye}(structured data)
+ {Wh}[{Gr}2{Wh}] {Cy}CSV only {Ye}(spreadsheet format)
+ {Wh}[{Gr}3{Wh}] {Cy}HTML only {Ye}(visual report)
+ {Wh}[{Gr}4{Wh}] {Cy}JSON + CSV
+ {Wh}[{Gr}5{Wh}] {Cy}JSON + HTML
+ {Wh}[{Gr}6{Wh}] {Cy}All formats {Ye}(JSON + CSV + HTML)
+ """)
+
+def get_export_format():
+ """Get export format choice from user"""
+ display_export_menu() # Show the menu before asking
+ choice = get_menu_choice("Choose export format", ['1', '2', '3', '4', '5', '6'])
+
+ format_map = {
+ '1': 'json',
+ '2': 'csv',
+ '3': 'html',
+ '4': 'json,csv',
+ '5': 'json,html',
+ '6': 'json,csv,html'
+ }
+
+ return format_map[choice]
+
+def get_target_input():
+ """Get single target username from user"""
+ print_info("Enter target username to analyze")
+ target = input(f"\n {Wh}[{Gr}>{Wh}] {Cy}Target username: {Ye}").strip()
+ return target
+
+def get_multiple_targets():
+ """Get multiple target usernames from user"""
+ print_info("Enter target usernames (one per line, empty line to finish)")
+ targets = []
+ count = 1
+
+ while True:
+ target = input(f" {Wh}[{Gr}{count}{Wh}] {Cy}Target: {Ye}").strip()
+ if not target:
+ break
+ targets.append(target)
+ count += 1
+
+ return targets
+
+def get_limit_options():
+ """Get follower/following limit options"""
+ print_header("DATA LIMITS")
+ print(f"""
+ {Wh}Set data fetching limits (for performance):
+
+ {Wh}[{Gr}1{Wh}] {Cy}No limits {Ye}(fetch all - may be slow)
+ {Wh}[{Gr}2{Wh}] {Cy}Limit to 100 each
+ {Wh}[{Gr}3{Wh}] {Cy}Limit to 500 each
+ {Wh}[{Gr}4{Wh}] {Cy}Limit to 1000 each
+ {Wh}[{Gr}5{Wh}] {Cy}Custom limits
+ """)
+
+ choice = get_menu_choice("Choose limit option", ['1', '2', '3', '4', '5'])
+
+ if choice == '1':
+ return None, None
+ elif choice == '2':
+ return 100, 100
+ elif choice == '3':
+ return 500, 500
+ elif choice == '4':
+ return 1000, 1000
+ elif choice == '5':
+ try:
+ followers = int(input(f" {Wh}[{Gr}?{Wh}] {Cy}Followers limit: {Ye}"))
+ following = int(input(f" {Wh}[{Gr}?{Wh}] {Cy}Following limit: {Ye}"))
+ return followers, following
+ except ValueError:
+ print_warning("Invalid number, using no limits")
+ return None, None
+
+def confirm_action(message):
+ """Ask user to confirm action"""
+ response = input(f"\n {Wh}[{Ye}?{Wh}] {message} {Ye}(y/n): {Wh}").strip().lower()
+ return response in ['y', 'yes']
+
+def display_summary(config):
+ """Display configuration summary before processing"""
+ print_header("CONFIGURATION SUMMARY")
+ print(f"\n {Cy}Features:")
+ print(f" {Wh}• Download Posts: {Gr if config.get('download') else Re}{'Yes' if config.get('download') else 'No'}")
+ print(f" {Wh}• Run Analytics: {Gr if config.get('analyze') else Re}{'Yes' if config.get('analyze') else 'No'}")
+ print(f" {Wh}• Save to Database: {Gr if config.get('db') else Re}{'Yes' if config.get('db') else 'No'}")
+
+ if config.get('limit_followers') or config.get('limit_following'):
+ print(f"\n {Cy}Limits:")
+ print(f" {Wh}• Followers: {Ye}{config.get('limit_followers', 'All')}")
+ print(f" {Wh}• Following: {Ye}{config.get('limit_following', 'All')}")
+
+ print(f"\n {Cy}Export Format: {Ye}{config.get('export_format', 'json')}")
+ print()
diff --git a/processor.py b/processor.py
new file mode 100644
index 0000000..27b40a2
--- /dev/null
+++ b/processor.py
@@ -0,0 +1,286 @@
+"""Core processor for Instagram OSINT operations"""
+
+import instaloader
+import time
+import os
+from utils import print_info, print_warning, print_error, print_success, print_header, loading_animation
+from analyzer import ProfileAnalytics, ComparativeAnalytics
+from exporter import Exporter
+from database import OsintDatabase
+
+SESSION_FILE = "session-{username}"
+DOWNLOAD_DIR = "downloads" # Directory for Instagram content
+
+class InstagramOSINT:
+ """Main processor for Instagram OSINT"""
+
+ def __init__(self, username=None, password=None, use_session=True, quiet=False):
+ self.username = username
+ self.password = password
+ self.use_session = use_session
+ self.quiet = quiet
+ self.loader = instaloader.Instaloader(dirname_pattern=DOWNLOAD_DIR + "/{target}")
+ self.is_logged_in = False
+
+ # Create download directory if it doesn't exist
+ os.makedirs(DOWNLOAD_DIR, exist_ok=True)
+
+ def load_session(self):
+ """Load saved session if available"""
+ if not self.use_session or not self.username:
+ return False
+
+ session_file = SESSION_FILE.format(username=self.username)
+ try:
+ self.loader.load_session_from_file(self.username, session_file)
+ self.is_logged_in = True
+ if not self.quiet:
+ print_success("Session loaded successfully!")
+ return True
+ except FileNotFoundError:
+ return False
+
+ def login(self, username, password):
+ """Handle login with 2FA support"""
+ self.username = username
+ self.password = password
+
+ try:
+ self.loader.login(username, password)
+ self.is_logged_in = True
+ self.save_session()
+ if not self.quiet:
+ print_success("Login successful!")
+ return True
+ except instaloader.exceptions.TwoFactorAuthRequiredException:
+ if not self.quiet:
+ print_warning("Two-factor authentication required!")
+ two_factor_code = input("Enter your 2FA code: ")
+ self.loader.two_factor_login(two_factor_code)
+ self.is_logged_in = True
+ self.save_session()
+ if not self.quiet:
+ print_success("Login successful with 2FA!")
+ return True
+ except Exception as e:
+ if not self.quiet:
+ print_error(f"Login failed: {str(e)}")
+ return False
+
+ def save_session(self):
+ """Save current session"""
+ if self.username:
+ session_file = SESSION_FILE.format(username=self.username)
+ self.loader.save_session_to_file(session_file)
+
+ def authenticate(self):
+ """Authenticate using session or login"""
+ if self.use_session and self.load_session():
+ return True
+
+ if self.username and self.password:
+ return self.login(self.username, self.password)
+
+ return False
+
+ def fetch_profile(self, target_username):
+ """Fetch profile data"""
+ if not self.is_logged_in:
+ print_error("Not logged in")
+ return None
+
+ try:
+ profile = instaloader.Profile.from_username(self.loader.context, target_username)
+ return profile
+ except instaloader.exceptions.ProfileNotExistsException:
+ print_error(f"Profile '{target_username}' does not exist")
+ return None
+ except Exception as e:
+ print_error(f"Error fetching profile: {str(e)}")
+ return None
+
+ def fetch_followers(self, profile, limit=None):
+ """Fetch followers list"""
+ try:
+ followers = []
+ count = 0
+ for follower in profile.get_followers():
+ followers.append({
+ "username": follower.username,
+ "user_id": follower.userid,
+ "full_name": follower.full_name
+ })
+ count += 1
+ if limit and count >= limit:
+ break
+
+ if not self.quiet:
+ print_success(f"Fetched {len(followers)} followers")
+ return followers
+ except Exception as e:
+ print_error(f"Error fetching followers: {str(e)}")
+ return []
+
+ def fetch_following(self, profile, limit=None):
+ """Fetch following list"""
+ try:
+ following = []
+ count = 0
+ for followee in profile.get_followees():
+ following.append({
+ "username": followee.username,
+ "user_id": followee.userid,
+ "full_name": followee.full_name
+ })
+ count += 1
+ if limit and count >= limit:
+ break
+
+ if not self.quiet:
+ print_success(f"Fetched {len(following)} following")
+ return following
+ except Exception as e:
+ print_error(f"Error fetching following: {str(e)}")
+ return []
+
+ def download_posts(self, profile):
+ """Download profile posts"""
+ if not self.is_logged_in:
+ return
+
+ try:
+ count = 0
+ for post in profile.get_posts():
+ self.loader.download_post(post, target=profile.username)
+ count += 1
+
+ if not self.quiet and count > 0:
+ print_success(f"Downloaded {count} posts")
+ except Exception as e:
+ if not self.quiet:
+ print_warning(f"Error downloading posts: {str(e)}")
+
+ def download_highlights(self, profile):
+ """Download profile highlights"""
+ if not self.is_logged_in:
+ return
+
+ try:
+ count = 0
+ for highlight in self.loader.get_highlights(profile):
+ for item in highlight.get_items():
+ self.loader.download_storyitem(item, target=profile.username)
+ count += 1
+
+ if not self.quiet and count > 0:
+ print_success(f"Downloaded {count} highlight items")
+ except Exception as e:
+ if not self.quiet:
+ print_warning(f"Error downloading highlights: {str(e)}")
+
+ def process_profile(self, target_username, options=None):
+ """Complete profile processing pipeline"""
+ options = options or {}
+
+ if not self.quiet:
+ print_header(f"PROCESSING {target_username}")
+
+ # Fetch profile
+ profile = self.fetch_profile(target_username)
+ if not profile:
+ return None
+
+ if not self.quiet:
+ print_info(f"Full Name: {profile.full_name}")
+ print_info(f"ID: {profile.userid}")
+ print_info(f"Followers: {profile.followers}")
+ print_info(f"Following: {profile.followees}")
+ print_info(f"Posts: {profile.mediacount}")
+
+ # Fetch followers and following
+ followers = self.fetch_followers(profile, options.get('limit_followers'))
+ following = self.fetch_following(profile, options.get('limit_following'))
+
+ # Calculate analytics
+ analytics = None
+ if options.get('analyze'):
+ analytics = ProfileAnalytics(profile).get_analytics_summary()
+ if not self.quiet and analytics:
+ print_header("ANALYTICS")
+ print_info(f"Profile Type: {analytics.get('profile_type')}")
+ print_info(f"Engagement Rate: {analytics.get('engagement_rate')}")
+ print_info(f"Follower Ratio: {analytics.get('follower_ratio')}")
+ print_info(f"Risk Score: {analytics.get('risk_score')}/100")
+
+ # Store in database
+ if options.get('db'):
+ db = OsintDatabase()
+ db.save_profile(profile)
+ db.save_followers(profile.username, followers)
+ if analytics:
+ db.save_analytics(profile.username, analytics)
+ if not self.quiet:
+ print_success("Data saved to database")
+
+ # Download content
+ if not options.get('no_download'):
+ self.download_posts(profile)
+ self.download_highlights(profile)
+
+ # Export data
+ results = {
+ "profile": profile,
+ "followers": followers,
+ "following": following,
+ "analytics": analytics
+ }
+
+ return results
+
+ def batch_process(self, target_list, options=None):
+ """Process multiple targets"""
+ options = options or {}
+ results = []
+
+ for target in target_list:
+ result = self.process_profile(target, options)
+ if result:
+ results.append(result)
+ time.sleep(2) # Rate limiting
+
+ return results
+
+ def export_results(self, results, target_username, formats='json'):
+ """Export results in specified formats"""
+ profile = results['profile']
+ followers = results['followers']
+ following = results['following']
+ analytics = results['analytics']
+
+ format_list = [f.strip().lower() for f in formats.split(',')]
+ exported_files = []
+
+ for fmt in format_list:
+ try:
+ if fmt == 'json':
+ file = Exporter.export_json(profile, followers, following, target_username, analytics)
+ exported_files.append(file)
+ if not self.quiet:
+ print_success(f"Exported to JSON: {file}")
+
+ elif fmt == 'csv':
+ files = Exporter.export_csv(profile, followers, following, target_username)
+ exported_files.extend(files)
+ if not self.quiet:
+ for file in files:
+ print_success(f"Exported to CSV: {file}")
+
+ elif fmt == 'html':
+ file = Exporter.export_html(profile, followers, following, target_username, analytics)
+ exported_files.append(file)
+ if not self.quiet:
+ print_success(f"Exported to HTML: {file}")
+ except Exception as e:
+ print_error(f"Error exporting to {fmt}: {str(e)}")
+
+ return exported_files
diff --git a/screenshots/01_login_screen.png b/screenshots/01_login_screen.png
new file mode 100644
index 0000000..e150941
Binary files /dev/null and b/screenshots/01_login_screen.png differ
diff --git a/screenshots/02_2fa_prompt.png b/screenshots/02_2fa_prompt.png
new file mode 100644
index 0000000..bc76e6d
Binary files /dev/null and b/screenshots/02_2fa_prompt.png differ
diff --git a/screenshots/03_features_config.png b/screenshots/03_features_config.png
new file mode 100644
index 0000000..cad6ea9
Binary files /dev/null and b/screenshots/03_features_config.png differ
diff --git a/screenshots/04_export_format.png b/screenshots/04_export_format.png
new file mode 100644
index 0000000..b7b284f
Binary files /dev/null and b/screenshots/04_export_format.png differ
diff --git a/screenshots/05_data_limits.png b/screenshots/05_data_limits.png
new file mode 100644
index 0000000..1665ef8
Binary files /dev/null and b/screenshots/05_data_limits.png differ
diff --git a/screenshots/06_config_summary.png b/screenshots/06_config_summary.png
new file mode 100644
index 0000000..3db5539
Binary files /dev/null and b/screenshots/06_config_summary.png differ
diff --git a/screenshots/07_processing.png b/screenshots/07_processing.png
new file mode 100644
index 0000000..ce4310d
Binary files /dev/null and b/screenshots/07_processing.png differ
diff --git a/screenshots/08_html_report.png b/screenshots/08_html_report.png
new file mode 100644
index 0000000..4771c4d
Binary files /dev/null and b/screenshots/08_html_report.png differ
diff --git a/ui.py b/ui.py
new file mode 100644
index 0000000..bda04d0
--- /dev/null
+++ b/ui.py
@@ -0,0 +1,251 @@
+"""Advanced terminal UI components"""
+
+import time
+import getpass
+from typing import List, Dict, Tuple
+from utils import (
+ Cy, Gr, Re, Ye, Wh, BrGr, BrCy, BrYe, BrRe,
+ Bold, Underline, Dim, Reset, CHECK, CROSS, INFO, ARROW
+)
+
+class TerminalUI:
+ """Advanced terminal UI components"""
+
+ @staticmethod
+ def print_header_banner(title, subtitle=""):
+ """Print an impressive header banner"""
+ width = 80
+ print(f"\n{Cy}{Bold}{'█' * width}{Reset}")
+ print(f"{Cy}█{Reset} {BrCy}{Bold}{title.center(width - 4)}{Reset} {Cy}█{Reset}")
+
+ if subtitle:
+ print(f"{Cy}█{Reset} {Dim}{subtitle.center(width - 4)}{Reset} {Cy}█{Reset}")
+
+ print(f"{Cy}{Bold}{'█' * width}{Reset}\n")
+
+ @staticmethod
+ def print_profile_table(profile_data: Dict):
+ """Print profile data in a nice table format"""
+ print(f"\n{BrCy}{Bold} 📊 PROFILE DATA{Reset}\n")
+
+ display_order = [
+ ("Username", "username"),
+ ("Full Name", "full_name"),
+ ("User ID", "userid"),
+ ("Bio", "biography"),
+ ("Followers", "followers"),
+ ("Following", "followees"),
+ ("Posts", "mediacount"),
+ ("Private", "is_private"),
+ ("Business", "is_business_account"),
+ ]
+
+ for label, key in display_order:
+ value = profile_data.get(key, "N/A")
+
+ # Format value
+ if isinstance(value, bool):
+ value_str = f"{BrGr}Yes{Reset}" if value else f"{Re}No{Reset}"
+ elif isinstance(value, int) and key in ["followers", "followees", "mediacount"]:
+ value_str = f"{BrCy}{value:,}{Reset}"
+ else:
+ value_str = str(value) if value else f"{Dim}N/A{Reset}"
+
+ label_width = 20
+ print(f" {ARROW} {label:<{label_width}} {Wh}{value_str}{Reset}")
+
+ @staticmethod
+ def print_stats_grid(stats: Dict[str, Tuple[str, str]]):
+ """Print statistics in a grid layout
+
+ stats = {
+ "Engagement": ("2.5", "posts/follower"),
+ "Follower Ratio": ("1.5", "followers/following")
+ }
+ """
+ print(f"\n{BrCy}{Bold} 📈 ANALYTICS{Reset}\n")
+
+ for label, (value, unit) in stats.items():
+ print(f" {CHECK} {Bold}{label:<25}{Reset} {BrGr}{value:>12}{Reset} {Dim}{unit}{Reset}")
+
+ @staticmethod
+ def print_followers_table(followers: List[Dict], limit=20):
+ """Print followers in a formatted table"""
+ print(f"\n{BrCy}{Bold} 👥 FOLLOWERS ({len(followers)}){Reset}\n")
+
+ # Header
+ header = ["#", "Username", "User ID", "Full Name"]
+ col_widths = [4, 20, 12, 25]
+
+ header_line = " " + " │ ".join(f"{h:^{w}}" for h, w in zip(header, col_widths))
+ print(f"{BrCy}{Bold}{header_line}{Reset}")
+
+ sep = " " + "─┼─".join("─" * w for w in col_widths)
+ print(f"{Cy}{sep}{Reset}")
+
+ # Data rows
+ for i, follower in enumerate(followers[:limit], 1):
+ row_data = [
+ str(i),
+ follower.get("username", "N/A")[:20],
+ str(follower.get("user_id", ""))[:12],
+ follower.get("full_name", "N/A")[:25]
+ ]
+ row_line = " " + " │ ".join(f"{d:<{w}}" for d, w in zip(row_data, col_widths))
+ print(f"{Wh}{row_line}{Reset}")
+
+ if len(followers) > limit:
+ remaining = len(followers) - limit
+ print(f"{Dim} ... and {remaining} more followers{Reset}\n")
+ else:
+ print()
+
+ @staticmethod
+ def print_risk_assessment(risk_score: int, profile_type: str):
+ """Print risk assessment with color coding"""
+ print(f"\n{BrCy}{Bold} ⚠️ RISK ASSESSMENT{Reset}\n")
+
+ # Risk level
+ if risk_score < 25:
+ risk_color = BrGr
+ risk_level = "LOW RISK"
+ elif risk_score < 50:
+ risk_color = BrYe
+ risk_level = "MEDIUM RISK"
+ elif risk_score < 75:
+ risk_color = Ye
+ risk_level = "HIGH RISK"
+ else:
+ risk_color = BrRe
+ risk_level = "CRITICAL RISK"
+
+ # Risk bar
+ filled = int(risk_score / 10)
+ bar = "█" * filled + "░" * (10 - filled)
+
+ print(f" Risk Score: {risk_color}{bar}{Reset} {risk_score}/100")
+ print(f" Level: {risk_color}{Bold}{risk_level}{Reset}")
+ print(f" Type: {BrCy}{profile_type}{Reset}\n")
+
+ @staticmethod
+ def print_comparison(profile1: Dict, profile2: Dict):
+ """Print side-by-side profile comparison"""
+ print(f"\n{BrCy}{Bold} 🔄 PROFILE COMPARISON{Reset}\n")
+
+ keys = ["followers", "followees", "mediacount"]
+
+ for key in keys:
+ label = key.replace("_", " ").title()
+ val1 = profile1.get(key, 0)
+ val2 = profile2.get(key, 0)
+
+ val1_str = f"{val1:,}" if isinstance(val1, int) else str(val1)
+ val2_str = f"{val2:,}" if isinstance(val2, int) else str(val2)
+
+ # Determine which is larger
+ if isinstance(val1, int) and isinstance(val2, int):
+ diff = val1 - val2
+ if diff > 0:
+ diff_str = f"{BrGr}+{diff:,}{Reset}"
+ elif diff < 0:
+ diff_str = f"{BrRe}{diff:,}{Reset}"
+ else:
+ diff_str = f"{Dim}Equal{Reset}"
+ else:
+ diff_str = ""
+
+ print(f" {label:<15} {BrCy}{val1_str:>12}{Reset} vs {BrCy}{val2_str:>12}{Reset} {diff_str}")
+
+ print()
+
+ @staticmethod
+ def print_step_progress(current: int, total: int, label: str):
+ """Print step-by-step progress"""
+ bar = "▰" * current + "▱" * (total - current)
+ percent = int((current / total) * 100)
+
+ print(f" {BrCy}{bar}{Reset} {BrGr}{percent:>3}%{Reset} - {label}")
+
+ @staticmethod
+ def print_export_summary(exports: List[Tuple[str, str]]):
+ """Print export file summary"""
+ print(f"\n{BrGr}{Bold} ✓ EXPORT COMPLETE{Reset}\n")
+
+ for file_type, filename in exports:
+ icon = "📄" if file_type == "JSON" else ("📊" if file_type == "CSV" else "🌐")
+ print(f" {icon} {Bold}{file_type:<8}{Reset} {Cy}{filename}{Reset}")
+
+ print()
+
+ @staticmethod
+ def print_database_summary(profile_count: int, follower_count: int):
+ """Print database operation summary"""
+ print(f"\n{BrGr}{Bold} ✓ DATABASE SAVED{Reset}\n")
+ print(f" {CHECK} Stored {BrCy}{profile_count}{Reset} profile snapshot(s)")
+ print(f" {CHECK} Stored {BrCy}{follower_count:,}{Reset} follower record(s)")
+ print()
+
+ @staticmethod
+ def print_loading_phase(phase: int, total_phases: int, phase_name: str):
+ """Print loading phase with animation"""
+ bar = "▰" * phase + "▱" * (total_phases - phase)
+ print(f"\r {Cy}{bar}{Reset} {BrCy}[{phase}/{total_phases}]{Reset} {phase_name:<40}", end="", flush=True)
+
+ @staticmethod
+ def print_success_box(message: str):
+ """Print success in a box"""
+ width = 78
+ print(f"\n {BrGr}╔{'═' * width}╗{Reset}")
+ print(f" {BrGr}║{Reset} {BrGr}{Bold}{message.center(width)}{Reset} {BrGr}║{Reset}")
+ print(f" {BrGr}╚{'═' * width}╝{Reset}\n")
+
+ @staticmethod
+ def print_error_box(message: str):
+ """Print error in a box"""
+ width = 78
+ print(f"\n {BrRe}╔{'═' * width}╗{Reset}")
+ print(f" {BrRe}║{Reset} {BrRe}{Bold}{message.center(width)}{Reset} {BrRe}║{Reset}")
+ print(f" {BrRe}╚{'═' * width}╝{Reset}\n")
+
+class InteractivePrompt:
+ """Interactive command-line prompts"""
+
+ @staticmethod
+ def get_credentials():
+ """Get credentials with styling - password hidden for security"""
+ print(f"\n{BrCy}{Bold} 🔐 INSTAGRAM CREDENTIALS{Reset}\n")
+
+ username = input(f" {ARROW} Username: {BrCy}")
+ print(Reset, end="")
+
+ # Use getpass to hide password input
+ password = getpass.getpass(f" {ARROW} Password: {BrCy}")
+ print(Reset, end="")
+
+ return username, password
+
+ @staticmethod
+ def get_target():
+ """Get target username"""
+ print(f"\n{BrCy}{Bold} 🎯 TARGET SELECTION{Reset}\n")
+ target = input(f" {ARROW} Target username: {BrCy}")
+ print(Reset, end="")
+ return target
+
+ @staticmethod
+ def confirm(message: str) -> bool:
+ """Get confirmation"""
+ response = input(f" {ARROW} {message} {BrCy}(y/n): {Reset}").lower().strip()
+ return response in ['y', 'yes']
+
+ @staticmethod
+ def select_options(options: List[str], title: str = "Select options") -> List[bool]:
+ """Multi-select options"""
+ print(f"\n{BrCy}{Bold} ⚙️ {title}{Reset}\n")
+
+ selections = []
+ for i, option in enumerate(options, 1):
+ response = input(f" {i}. {option}? {BrCy}(y/n): {Reset}").lower().strip()
+ selections.append(response in ['y', 'yes'])
+
+ return selections
diff --git a/utils.py b/utils.py
new file mode 100644
index 0000000..e9ef91e
--- /dev/null
+++ b/utils.py
@@ -0,0 +1,240 @@
+"""Utility functions for Instagram OSINT"""
+
+import sys
+import time
+from typing import List
+
+# Color variables
+Bl = '\033[30m'
+Re = '\033[1;31m'
+Gr = '\033[1;32m'
+Ye = '\033[1;33m'
+Blu = '\033[1;34m'
+Mage = '\033[1;35m'
+Cy = '\033[1;36m'
+Wh = '\033[1;37m'
+
+# Reset color
+Reset = '\033[0m'
+
+# Bright colors
+BrRe = '\033[91m'
+BrGr = '\033[92m'
+BrYe = '\033[93m'
+BrBlu = '\033[94m'
+BrMa = '\033[95m'
+BrCy = '\033[96m'
+
+# Background colors
+BgGr = '\033[42m'
+BgRe = '\033[41m'
+BgYe = '\033[43m'
+BgBlu = '\033[44m'
+
+# Formatting
+Bold = '\033[1m'
+Dim = '\033[2m'
+Italic = '\033[3m'
+Underline = '\033[4m'
+
+# Symbols
+CHECK = f"{Gr}✓{Reset}"
+CROSS = f"{Re}✗{Reset}"
+INFO = f"{Blu}ℹ{Reset}"
+WARN = f"{Ye}⚠{Reset}"
+STAR = f"{Ye}★{Reset}"
+ARROW = f"{Cy}→{Reset}"
+BULLET = f"{Gr}●{Reset}"
+LINE = "─" * 80
+
+def print_logo():
+ """Print the application logo"""
+ logo = f"""{Gr}
+
+ {Gr}██╗███╗ ██╗███████╗████████╗ █████╗ {Re}██████╗ ███████╗██╗███╗ ██╗████████╗
+ {Gr}██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗ {Re}██╔═══██╗██╔════╝██║████╗ ██║╚══██╔══╝
+ {Gr}██║██╔██╗ ██║███████╗ ██║ ███████║{Wh}█████╗{Re}██║ ██║███████╗██║██╔██╗ ██║ ██║
+ {Gr}██║██║╚██╗██║╚════██║ ██║ ██╔══██║{Wh}╚════╝{Re}██║ ██║╚════██║██║██║╚██╗██║ ██║
+ {Gr}██║██║ ╚████║███████║ ██║ ██║ ██║ {Re}╚██████╔╝███████║██║██║ ╚████║ ██║
+ {Gr}╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ {Re}╚═════╝ ╚══════╝╚═╝╚═╝ ╚═══╝ ╚═╝
+
+ {Wh}{Bold}INSTAGRAM OSINT INTELLIGENCE GATHERING TOOL{Reset}
+ {Cy}{Dim}Advanced Profile Analysis & Data Collection{Reset}
+ """
+ print(logo)
+
+def print_section(title, subtitle=""):
+ """Print a formatted section header"""
+ print(f"\n{Cy}{Bold}{LINE}{Reset}")
+ print(f"{Cy}{Bold} {title.upper()}{Reset}")
+ if subtitle:
+ print(f"{Dim}{Cy} {subtitle}{Reset}")
+ print(f"{Cy}{Bold}{LINE}{Reset}\n")
+
+def print_info(message, prefix=""):
+ """Print info message"""
+ icon = INFO if not prefix else prefix
+ print(f" {icon} {Wh}{message}{Reset}")
+
+def print_success(message, prefix=""):
+ """Print success message"""
+ icon = CHECK if not prefix else prefix
+ print(f" {icon} {BrGr}{message}{Reset}")
+
+def print_warning(message, prefix=""):
+ """Print warning message"""
+ icon = WARN if not prefix else prefix
+ print(f" {icon} {BrYe}{message}{Reset}")
+
+def print_error(message, prefix=""):
+ """Print error message"""
+ icon = CROSS if not prefix else prefix
+ print(f" {icon} {BrRe}{message}{Reset}")
+
+def print_highlight(message):
+ """Print highlighted message"""
+ print(f" {STAR} {Bold}{BrCy}{message}{Reset}")
+
+def print_header(title):
+ """Print section header"""
+ print(f"\n{BgBlu}{Wh}{Bold} {title.upper()} {Reset}\n")
+
+def print_subheader(title):
+ """Print subsection header"""
+ print(f"\n{Cy}{Underline}{title}{Reset}\n")
+
+def print_data(key, value, color=Wh):
+ """Print key-value pair"""
+ print(f" {ARROW} {Cyan}{Bold}{key}{Reset}: {color}{value}{Reset}")
+
+def print_table_row(columns: List[str], widths: List[int], is_header=False, color=Wh):
+ """Print a formatted table row"""
+ row = " │ ".join(
+ f"{col:<{width}}" if i == 0 else f"{col:^{width}}"
+ for i, (col, width) in enumerate(zip(columns, widths))
+ )
+
+ if is_header:
+ print(f" {BgBlu}{Wh}{Bold}{row}{Reset}")
+ separator = " ├─" + "─┼─".join("─" * w for w in widths) + "─┤"
+ print(f" {Cy}{separator}{Reset}")
+ else:
+ print(f" {color}{row}{Reset}")
+
+def loading_animation(message="", duration=3):
+ """Show loading animation"""
+ frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
+ start = time.time()
+
+ while time.time() - start < duration:
+ for frame in frames:
+ sys.stdout.write(f"\r {Cy}{frame}{Reset} {message}")
+ sys.stdout.flush()
+ time.sleep(0.08)
+
+def progress_bar(current, total, width=50, label="", color=Gr):
+ """Display a progress bar"""
+ if total == 0:
+ return
+
+ percent = current / total
+ filled = int(width * percent)
+ bar = "█" * filled + "░" * (width - filled)
+
+ percentage = f"{int(percent * 100):>3}%"
+ count_str = f"[{current}/{total}]"
+
+ if label:
+ print(f" {label}")
+
+ print(f" {color}{bar}{Reset} {percentage} {count_str}")
+
+def spinner(duration=3, label=""):
+ """Show a spinner"""
+ frames = ["◐", "◓", "◑", "◒"]
+ start = time.time()
+ frame_idx = 0
+
+ while time.time() - start < duration:
+ sys.stdout.write(f"\r {Cy}{frames[frame_idx % len(frames)]}{Reset} {label}")
+ sys.stdout.flush()
+ time.sleep(0.2)
+ frame_idx += 1
+
+ sys.stdout.write(f"\r {CHECK} {label}\n")
+ sys.stdout.flush()
+
+def print_box(title, content, color=Cy):
+ """Print content in a box"""
+ border_top = f" {color}╔════════════════════════════════════════════════════════════════════════════════╗{Reset}"
+ border_mid = f" {color}║{Reset}"
+ border_bot = f" {color}╚════════════════════════════════════════════════════════════════════════════════╝{Reset}"
+
+ print(border_top)
+ if title:
+ title_str = f" {Bold}{title}{Reset} "
+ print(f"{border_mid} {title_str:<78} {border_mid}")
+ print(f" {color}╠════════════════════════════════════════════════════════════════════════════════╣{Reset}")
+
+ for line in content.split('\n'):
+ padding = 78 - len(line)
+ print(f"{border_mid} {line:<{padding}} {border_mid}")
+
+ print(border_bot)
+
+def print_stat(label, value, unit="", color=BrCy):
+ """Print a statistic with formatting"""
+ print(f" {BULLET} {Bold}{label}{Reset}: {color}{value:,}{Reset} {Dim}{unit}{Reset}")
+
+def print_menu(options: List[str], title="Select an option"):
+ """Print an interactive menu"""
+ print(f"\n{Cy}{Bold}{title}{Reset}")
+ for i, option in enumerate(options, 1):
+ print(f" {BrCy}{i}{Reset} {Wh}{option}{Reset}")
+
+ while True:
+ try:
+ choice = input(f"\n {Gr}Enter your choice (1-{len(options)}): {Reset}")
+ choice = int(choice)
+ if 1 <= choice <= len(options):
+ return choice
+ else:
+ print_warning("Invalid choice. Please try again.")
+ except ValueError:
+ print_warning("Please enter a valid number.")
+
+def clear_screen():
+ """Clear terminal screen"""
+ import os
+ os.system('clear' if sys.platform != 'win32' else 'cls')
+
+def print_divider(char="=", length=80):
+ """Print a divider line"""
+ print(f" {Cy}{char * length}{Reset}")
+
+def print_profile_card(profile_data: dict):
+ """Print a formatted profile card"""
+ print(f"\n{BgBlu}{Wh}{Bold} PROFILE INFORMATION {Reset}\n")
+
+ for key, value in profile_data.items():
+ key_display = key.replace('_', ' ').title()
+ if isinstance(value, bool):
+ value = f"{BrGr}Yes{Reset}" if value else f"{Re}No{Reset}"
+ else:
+ value = str(value) if value else f"{Dim}N/A{Reset}"
+ print(f" {Cy}▸{Reset} {Bold}{key_display:<25}{Reset} {Wh}{value}{Reset}")
+
+def print_comparison_header(title1, title2):
+ """Print header for comparison"""
+ print(f"\n{Cy}{Bold}{LINE}{Reset}")
+ print(f" {BrCy}{title1:<35}{Reset} │ {BrCy}{title2:<35}{Reset}")
+ print(f"{Cy}{Bold}{LINE}{Reset}\n")
+
+def format_large_number(num):
+ """Format large numbers for display"""
+ if num >= 1_000_000:
+ return f"{num / 1_000_000:.1f}M"
+ elif num >= 1_000:
+ return f"{num / 1_000:.1f}K"
+ return str(num)
+