109 lines
3.2 KiB
Bash
Executable File
109 lines
3.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# Upwork Auto-Apply Pipeline
|
|
# Called by Clawdbot wake event when new Upwork email arrives
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
ACCOUNT="jake@localbosses.org"
|
|
PROCESSED_FILE="$SCRIPT_DIR/processed.json"
|
|
MIN_HOURLY=50
|
|
MIN_FIXED=1000
|
|
|
|
# Initialize processed file if missing
|
|
[ -f "$PROCESSED_FILE" ] || echo '[]' > "$PROCESSED_FILE"
|
|
|
|
echo "[pipeline] Checking for new Upwork job emails..."
|
|
|
|
# Search for unread Upwork job notification emails
|
|
EMAILS=$(gog gmail search "from:donotreply@upwork.com subject:\"New job\" is:unread" \
|
|
--max 10 --account "$ACCOUNT" --json 2>&1)
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "[pipeline] ERROR: Gmail search failed: $EMAILS"
|
|
exit 1
|
|
fi
|
|
|
|
# Parse email IDs
|
|
EMAIL_IDS=$(echo "$EMAILS" | jq -r '.[].messages[0].id // empty' 2>/dev/null)
|
|
|
|
if [ -z "$EMAIL_IDS" ]; then
|
|
echo "[pipeline] No new Upwork job emails found."
|
|
exit 0
|
|
fi
|
|
|
|
PROCESSED_COUNT=0
|
|
SKIPPED_COUNT=0
|
|
|
|
for MSG_ID in $EMAIL_IDS; do
|
|
# Skip already processed
|
|
if jq -e "index(\"$MSG_ID\")" "$PROCESSED_FILE" > /dev/null 2>&1; then
|
|
echo "[pipeline] Already processed: $MSG_ID"
|
|
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
continue
|
|
fi
|
|
|
|
echo "[pipeline] Processing email: $MSG_ID"
|
|
|
|
# Get full email
|
|
EMAIL_BODY=$(gog gmail get "$MSG_ID" --account "$ACCOUNT" --json 2>&1)
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "[pipeline] ERROR reading email $MSG_ID: $EMAIL_BODY"
|
|
continue
|
|
fi
|
|
|
|
# Extract job URL
|
|
JOB_URL=$(echo "$EMAIL_BODY" | jq -r '.body // .snippet // ""' | \
|
|
grep -oP 'https://www\.upwork\.com/jobs/~\d+' | head -1)
|
|
|
|
if [ -z "$JOB_URL" ]; then
|
|
# Try plain text extraction
|
|
JOB_URL=$(gog gmail get "$MSG_ID" --account "$ACCOUNT" 2>&1 | \
|
|
grep -oP 'https://www\.upwork\.com/jobs/~\d+' | head -1)
|
|
fi
|
|
|
|
if [ -z "$JOB_URL" ]; then
|
|
echo "[pipeline] No job URL found in email $MSG_ID, skipping"
|
|
continue
|
|
fi
|
|
|
|
# Extract subject for logging
|
|
SUBJECT=$(echo "$EMAIL_BODY" | jq -r '.subject // "unknown"' 2>/dev/null || echo "unknown")
|
|
|
|
echo "[pipeline] Job URL: $JOB_URL"
|
|
echo "[pipeline] Subject: $SUBJECT"
|
|
|
|
# Extract rate info from email body
|
|
RATE_INFO=$(gog gmail get "$MSG_ID" --account "$ACCOUNT" 2>&1 | \
|
|
grep -E '^\s*(Hourly|Fixed)' | head -1 || echo "")
|
|
|
|
echo "[pipeline] Rate: $RATE_INFO"
|
|
|
|
# Quick pre-filter based on email rate info
|
|
if echo "$RATE_INFO" | grep -qi "hourly"; then
|
|
MAX_RATE=$(echo "$RATE_INFO" | grep -oP '\$\d+' | tail -1 | tr -d '$')
|
|
if [ -n "$MAX_RATE" ] && [ "$MAX_RATE" -lt "$MIN_HOURLY" ]; then
|
|
echo "[pipeline] SKIP: Max hourly rate \$$MAX_RATE < \$$MIN_HOURLY minimum"
|
|
# Mark as processed so we don't revisit
|
|
jq ". + [\"$MSG_ID\"]" "$PROCESSED_FILE" > "$PROCESSED_FILE.tmp" && mv "$PROCESSED_FILE.tmp" "$PROCESSED_FILE"
|
|
SKIPPED_COUNT=$((SKIPPED_COUNT + 1))
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
# Output job info for Clawdbot to process
|
|
echo "---JOB_DATA---"
|
|
echo "MSG_ID=$MSG_ID"
|
|
echo "JOB_URL=$JOB_URL"
|
|
echo "SUBJECT=$SUBJECT"
|
|
echo "RATE_INFO=$RATE_INFO"
|
|
echo "---END_JOB_DATA---"
|
|
|
|
# Mark as processed
|
|
jq ". + [\"$MSG_ID\"]" "$PROCESSED_FILE" > "$PROCESSED_FILE.tmp" && mv "$PROCESSED_FILE.tmp" "$PROCESSED_FILE"
|
|
PROCESSED_COUNT=$((PROCESSED_COUNT + 1))
|
|
|
|
done
|
|
|
|
echo "[pipeline] Done. Processed: $PROCESSED_COUNT, Skipped: $SKIPPED_COUNT"
|