HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //proc/thread-self/root/workspace/find_missing.py
#!/usr/bin/env python3
"""
Find the remaining ~1319 tweets that the day-windowed search missed.
Try multiple search strategies:
1. filter:replies (only replies)
2. filter:links (tweets with links)  
3. filter:media (tweets with media)
4. min_faves:0 (everything with at least 0 likes)
5. exclude:retweets (non-RTs only)
6. Different keyword/hashtag combinations
7. Longer time windows (monthly with different offsets)
"""
import json, subprocess, time, sys
from datetime import date, timedelta

WRAPPER = "/root/clawd/skills/x-twitter/scripts/x_twitter.py"
PROFILE = "datathrop"
SEEN_FILE = "/workspace/datathrop_progress.json"
OUTPUT_FILE = "/workspace/missing_tweets.jsonl"
LOG_FILE = "/workspace/find_missing.log"
DELAY = 3.0

# Load already-seen IDs
with open(SEEN_FILE) as f:
    progress = json.load(f)
seen = set(progress.get('seen_ids', []))
print(f"Already seen: {len(seen)} IDs")

new_tweets = []

def search(query, label=""):
    """Run a search and return new (unseen) tweets."""
    global new_tweets
    for attempt in range(5):
        r = subprocess.run(
            ['python3', WRAPPER, '--profile-key', PROFILE, 'search', query, '--count', '100', '--all'],
            capture_output=True, text=True, timeout=120
        )
        if r.returncode != 0:
            if '429' in r.stderr:
                print(f"  429 ({label}), waiting 90s...")
                time.sleep(90)
                continue
            print(f"  ERROR ({label}): {r.stderr[:200]}")
            return 0
        
        try:
            data = json.loads(r.stdout)
            tweets = data if isinstance(data, list) else data.get('tweets', [])
        except:
            return 0
        
        count = 0
        for t in tweets:
            if not isinstance(t, dict):
                continue
            tid = t.get('id')
            if tid and tid not in seen:
                seen.add(tid)
                new_tweets.append(t)
                count += 1
        
        if count:
            print(f"  {label}: +{count} new (total new: {len(new_tweets)})")
            with open(OUTPUT_FILE, 'a') as f:
                for t in tweets:
                    if isinstance(t, dict) and t.get('id'):
                        f.write(json.dumps(t) + '\n')
        return count
    
    print(f"  GAVE UP ({label})")
    return 0

# Strategy 1: Monthly windows with filter:replies (replies often missed)
print("\n=== Strategy 1: filter:replies monthly ===")
start = date(2011, 7, 1)
end = date(2026, 3, 13)
month = start
while month < end:
    next_month = date(month.year + month.month // 12, month.month % 12 + 1, 1)
    q = f"from:datathrop filter:replies since:{month.isoformat()} until:{next_month.isoformat()}"
    search(q, f"replies {month:%Y-%m}")
    month = next_month
    time.sleep(DELAY)

# Strategy 2: Monthly windows with exclude:retweets 
print("\n=== Strategy 2: exclude:retweets monthly ===")
month = start
while month < end:
    next_month = date(month.year + month.month // 12, month.month % 12 + 1, 1)
    q = f"from:datathrop exclude:retweets since:{month.isoformat()} until:{next_month.isoformat()}"
    search(q, f"no-rt {month:%Y-%m}")
    month = next_month
    time.sleep(DELAY)

# Strategy 3: Monthly with filter:links
print("\n=== Strategy 3: filter:links monthly ===")
month = start
while month < end:
    next_month = date(month.year + month.month // 12, month.month % 12 + 1, 1)
    q = f"from:datathrop filter:links since:{month.isoformat()} until:{next_month.isoformat()}"
    search(q, f"links {month:%Y-%m}")
    month = next_month
    time.sleep(DELAY)

# Strategy 4: Monthly with filter:media
print("\n=== Strategy 4: filter:media monthly ===")
month = start
while month < end:
    next_month = date(month.year + month.month // 12, month.month % 12 + 1, 1)
    q = f"from:datathrop filter:media since:{month.isoformat()} until:{next_month.isoformat()}"
    search(q, f"media {month:%Y-%m}")
    month = next_month
    time.sleep(DELAY)

# Strategy 5: Monthly with min_faves:1 (popular tweets that might be indexed differently)
print("\n=== Strategy 5: min_faves:1 monthly ===")
month = start
while month < end:
    next_month = date(month.year + month.month // 12, month.month % 12 + 1, 1)
    q = f"from:datathrop min_faves:1 since:{month.isoformat()} until:{next_month.isoformat()}"
    search(q, f"popular {month:%Y-%m}")
    month = next_month
    time.sleep(DELAY)

# Strategy 6: Try half-day windows for years that had many tweets
# High-activity years: 2013, 2014, 2015, 2017, 2018, 2019
print("\n=== Strategy 6: Half-day windows for high-activity periods ===")
for year in [2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021]:
    # Try with different search operators that might surface different tweets
    q = f"from:datathrop OR to:datathrop since:{year}-01-01 until:{year+1}-01-01"
    search(q, f"from/to {year}")
    time.sleep(DELAY)

print(f"\n=== TOTAL NEW FOUND: {len(new_tweets)} ===")