#!/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"