DinoPLayZ commited on
Commit
b859aa9
·
verified ·
1 Parent(s): 078a727

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +101 -86
main.py CHANGED
@@ -6,18 +6,6 @@ from datetime import datetime
6
  from dotenv import load_dotenv
7
  import threading
8
  from http.server import BaseHTTPRequestHandler, HTTPServer
9
- import socket
10
-
11
- # --- Hugging Face DNS Workaround ---
12
- # Hugging Face Spaces often fail to resolve 'api.telegram.org' via DNS.
13
- # We monkey-patch socket.getaddrinfo to force it to use Telegram's known IP.
14
- _old_getaddrinfo = socket.getaddrinfo
15
- def _new_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
16
- if host.lower() == 'api.telegram.org':
17
- return [(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, '', ('149.154.167.220', port))]
18
- return _old_getaddrinfo(host, port, family, type, proto, flags)
19
- socket.getaddrinfo = _new_getaddrinfo
20
- # -----------------------------------
21
 
22
  # Load optional .env if present in same directory
23
  load_dotenv()
@@ -28,9 +16,13 @@ load_dotenv()
28
  # Environment values (Make sure to populate your .env file)
29
  # We will reload these inside the loop so you can change them on the fly.
30
 
31
- # Telegram settings (Optional, loaded from .env or hardcoded here)
32
- TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "")
33
- TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID", "")
 
 
 
 
34
 
35
  # App check interval in seconds (default 60 secs = 1 min)
36
  CHECK_INTERVAL_SECONDS = 60
@@ -50,9 +42,15 @@ EXPIRED_BIP = None
50
 
51
 
52
  # ==============================================================================
53
- # TELEGRAM NOTIFIER
54
  # ==============================================================================
55
- TELEGRAM_OFFSET = None
 
 
 
 
 
 
56
 
57
  def update_env_file(new_xsrf, new_bip):
58
  env_path = ".env"
@@ -82,31 +80,40 @@ def update_env_file(new_xsrf, new_bip):
82
  if new_bip is not None and not bip_updated:
83
  f.write(f'BIP_SESSION="{new_bip}"\n')
84
 
85
- def check_telegram_messages():
86
- global TELEGRAM_OFFSET, SESSION_EXPIRED, EXPIRED_XSRF, EXPIRED_BIP
87
- if not TELEGRAM_BOT_TOKEN: return False
88
 
89
- url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/getUpdates"
90
- params = {"timeout": 5}
91
- if TELEGRAM_OFFSET:
92
- params["offset"] = TELEGRAM_OFFSET
93
-
94
  try:
95
- r = requests.get(url, params=params, timeout=10)
96
- data = r.json()
97
- cookies_updated = False
98
- if data.get("ok"):
99
- for result in data.get("result", []):
100
- TELEGRAM_OFFSET = result["update_id"] + 1
101
- msg = result.get("message", {})
102
- text = msg.get("text", "").strip()
103
- chat_id = msg.get("chat", {}).get("id")
104
-
105
- # Only process messages from our authorized user
106
- if str(chat_id) == str(TELEGRAM_CHAT_ID):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  new_xsrf = None
108
  new_bip = None
109
- for line in text.replace("\r", "\n").split("\n"):
110
  line = line.strip()
111
  if line.startswith("XSRF_TOKEN=") or line.startswith("XSRF-TOKEN="):
112
  parts = line.split("=", 1)
@@ -116,45 +123,51 @@ def check_telegram_messages():
116
  parts = line.split("=", 1)
117
  if len(parts) > 1:
118
  new_bip = parts[1].strip(' "\'')
119
-
120
  if new_xsrf or new_bip:
121
  update_env_file(new_xsrf, new_bip)
122
- send_telegram_message("✅ <b>Cookies Received!</b>\n\nI have updated the <code>.env</code> file and will now resume checking the BIP portal.")
123
  SESSION_EXPIRED = False
124
  EXPIRED_XSRF = None
125
  EXPIRED_BIP = None
126
- cookies_updated = True
127
- print(f"[{datetime.now().strftime('%I:%M:%S %p')}] 🔄 Cookies received via Telegram! Resuming checks...")
128
- return cookies_updated
129
  except Exception as e:
130
- print(f"[DEBUG] Network/Request EXCEPTION in check_telegram_messages: {type(e).__name__} - {e}")
131
  return False
132
-
133
- def send_telegram_message(text: str):
134
- print(f"\n[DEBUG] --> send_telegram_message called")
135
- if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
136
- print("\n[!] Telegram not configured. The following alert would have been sent:\n")
137
- print(text)
 
138
  print("-" * 50)
139
  return False
140
 
141
- url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
142
- payload = {
143
- "chat_id": TELEGRAM_CHAT_ID,
144
- "text": text,
145
- "parse_mode": "HTML",
146
- "disable_web_page_preview": True
147
- }
148
-
149
  try:
150
- print(f"[DEBUG] Sending alert to Telegram API...")
151
- r = requests.post(url, json=payload, timeout=10)
152
- print(f"[DEBUG] Telegram responded with HTTP {r.status_code}")
153
- r.raise_for_status()
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  return True
155
  except Exception as e:
156
- print(f"[DEBUG] Network/Request EXCEPTION in send_telegram_message: {type(e).__name__} - {e}")
157
- print(f"[!] Failed to send telegram message: {e}")
158
  return False
159
 
160
  def send_event_alerts(events):
@@ -176,17 +189,17 @@ def send_event_alerts(events):
176
 
177
  msg += (
178
  f"<b>{ev.get('event_code', '-')} - "
179
- f"{ev.get('event_name', 'Unknown')}</b>\n\n"
180
- f"{ev.get('event_category', '-')}\n\n"
181
- f"{start} to {end}\n\n"
182
- f"{ev.get('location', '-')}\n\n"
183
- f"{ev.get('status', '-')}\n\n"
184
  f"Seats: Max {ev.get('maximum_count', '-')} | "
185
- f"Applied {ev.get('applied_count', '-')}\n"
186
- f"<a href='{ev.get('web_url', '#')}'>View Event Here</a>\n"
187
- f"────────────────\n"
188
  )
189
- send_telegram_message(msg)
190
 
191
 
192
  # ==============================================================================
@@ -292,12 +305,14 @@ def process_tick():
292
 
293
  if err:
294
  print(f"{time_str.lower()} - ❌ Error scraping events: {err}")
295
- send_telegram_message(
296
- "⚠️ <b>Scraper Error!</b>\n\n"
297
- f"The notifier encountered an error and has paused checking. Error:\n"
298
- f"<code>{err}</code>\n\n"
299
- "Please reply directly to this bot with your new cookies in this format to resume:\n\n"
300
- "<code>XSRF_TOKEN=your_new_token_here\nBIP_SESSION=your_new_session_here</code>"
 
 
301
  )
302
  SESSION_EXPIRED = True
303
  EXPIRED_XSRF = xsrf
@@ -376,10 +391,10 @@ def get_latest_event():
376
  print(f"Link: {ev.get('web_url')}")
377
  print("-" * 60)
378
 
379
- def test_telegram_alert():
380
- """Sends a dummy test message to the configured Telegram chat."""
381
- print("Sending test exact alert to Telegram...")
382
- success = send_telegram_message("🤖 <b>Test Alert from BIP CLI Notifier</b>\n\nYour Telegram integration is working perfectly!")
383
  if success:
384
  print("✅ Test message sent successfully!")
385
  else:
@@ -399,7 +414,7 @@ def start_loop():
399
  target_time = time.time() + CHECK_INTERVAL_SECONDS
400
 
401
  while time.time() < target_time:
402
- cookies_updated = check_telegram_messages()
403
  if cookies_updated:
404
  # User sent new cookies, immediately break to run process_tick right now!
405
  break
@@ -436,7 +451,7 @@ if __name__ == "__main__":
436
  parser = argparse.ArgumentParser(description="BIP Cloud Notifier CLI")
437
  parser.add_argument("--list-all", action="store_true", help="List all recent events and exit")
438
  parser.add_argument("--latest", action="store_true", help="Print details of the latest event and exit")
439
- parser.add_argument("--test-alert", action="store_true", help="Send a test message to Telegram and exit")
440
  parser.add_argument("--run", action="store_true", help="Start the continuous 1-minute monitoring loop")
441
  print("Parsed arguments:", parser.parse_args())
442
  args = parser.parse_args()
@@ -446,7 +461,7 @@ if __name__ == "__main__":
446
  elif args.latest:
447
  get_latest_event()
448
  elif args.test_alert:
449
- test_telegram_alert()
450
  elif args.run:
451
  threading.Thread(target=run_dummy_server, daemon=True).start()
452
  start_loop()
 
6
  from dotenv import load_dotenv
7
  import threading
8
  from http.server import BaseHTTPRequestHandler, HTTPServer
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  # Load optional .env if present in same directory
11
  load_dotenv()
 
16
  # Environment values (Make sure to populate your .env file)
17
  # We will reload these inside the loop so you can change them on the fly.
18
 
19
+ # Email settings (Loaded from .env)
20
+ # The email you are sending FROM and TO (can be the same)
21
+ EMAIL_ADDRESS = os.getenv("EMAIL_ADDRESS", "")
22
+ # Gmail App Password (NOT your regular password)
23
+ EMAIL_PASSWORD = os.getenv("EMAIL_PASSWORD", "")
24
+ # Notification recipient
25
+ EMAIL_RECIPIENT = os.getenv("EMAIL_RECIPIENT", EMAIL_ADDRESS)
26
 
27
  # App check interval in seconds (default 60 secs = 1 min)
28
  CHECK_INTERVAL_SECONDS = 60
 
42
 
43
 
44
  # ==============================================================================
45
+ # EMAIL NOTIFIER
46
  # ==============================================================================
47
+ import smtplib
48
+ from email.mime.text import MIMEText
49
+ from email.mime.multipart import MIMEMultipart
50
+ import imaplib
51
+ import email
52
+
53
+ LAST_SEEN_EMAIL_UID = None
54
 
55
  def update_env_file(new_xsrf, new_bip):
56
  env_path = ".env"
 
80
  if new_bip is not None and not bip_updated:
81
  f.write(f'BIP_SESSION="{new_bip}"\n')
82
 
83
+ def check_email_for_cookies():
84
+ global LAST_SEEN_EMAIL_UID, SESSION_EXPIRED, EXPIRED_XSRF, EXPIRED_BIP
85
+ if not EMAIL_ADDRESS or not EMAIL_PASSWORD: return False
86
 
 
 
 
 
 
87
  try:
88
+ # Connect to Gmail IMAP
89
+ mail = imaplib.IMAP4_SSL('imap.gmail.com')
90
+ mail.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
91
+ mail.select('inbox')
92
+
93
+ # Search for unread emails with our specific subject
94
+ status, messages = mail.search(None, '(UNSEEN SUBJECT "BIP_COOKIES")')
95
+ if status != 'OK': return False
96
+
97
+ cookie_updated = False
98
+ message_ids = messages[0].split()
99
+
100
+ for msg_id in message_ids:
101
+ status, msg_data = mail.fetch(msg_id, '(RFC822)')
102
+ for response_part in msg_data:
103
+ if isinstance(response_part, tuple):
104
+ msg = email.message_from_bytes(response_part[1])
105
+ if msg.is_multipart():
106
+ for part in msg.walk():
107
+ if part.get_content_type() == "text/plain":
108
+ text = part.get_payload(decode=True).decode()
109
+ break
110
+ else:
111
+ text = msg.get_payload(decode=True).decode()
112
+
113
+ # Process text
114
  new_xsrf = None
115
  new_bip = None
116
+ for line in text.split("\n"):
117
  line = line.strip()
118
  if line.startswith("XSRF_TOKEN=") or line.startswith("XSRF-TOKEN="):
119
  parts = line.split("=", 1)
 
123
  parts = line.split("=", 1)
124
  if len(parts) > 1:
125
  new_bip = parts[1].strip(' "\'')
126
+
127
  if new_xsrf or new_bip:
128
  update_env_file(new_xsrf, new_bip)
129
+ send_email_message("Cookies Received", "✅ Cookies Received!\n\nI have updated the .env file and will now resume checking the BIP portal.")
130
  SESSION_EXPIRED = False
131
  EXPIRED_XSRF = None
132
  EXPIRED_BIP = None
133
+ cookie_updated = True
134
+ print(f"[{datetime.now().strftime('%I:%M:%S %p')}] 🔄 Cookies received via Email! Resuming checks...")
135
+ return cookie_updated
136
  except Exception as e:
137
+ print(f"[DEBUG] IMAP EXCEPTION: {e}")
138
  return False
139
+
140
+ def send_email_message(subject: str, body: str, is_html=False):
141
+ print(f"\n[DEBUG] --> send_email_message called")
142
+ if not EMAIL_ADDRESS or not EMAIL_PASSWORD or not EMAIL_RECIPIENT:
143
+ print("\n[!] Email credentials not configured. The following alert would have been sent:\n")
144
+ print(f"Subject: {subject}")
145
+ print(body)
146
  print("-" * 50)
147
  return False
148
 
 
 
 
 
 
 
 
 
149
  try:
150
+ msg = MIMEMultipart()
151
+ msg['From'] = EMAIL_ADDRESS
152
+ msg['To'] = EMAIL_RECIPIENT
153
+ msg['Subject'] = subject
154
+
155
+ if is_html:
156
+ msg.attach(MIMEText(body, 'html'))
157
+ else:
158
+ msg.attach(MIMEText(body, 'plain'))
159
+
160
+ server = smtplib.SMTP('smtp.gmail.com', 587)
161
+ server.starttls()
162
+ server.login(EMAIL_ADDRESS, EMAIL_PASSWORD)
163
+ text = msg.as_string()
164
+ server.sendmail(EMAIL_ADDRESS, EMAIL_RECIPIENT, text)
165
+ server.quit()
166
+ print(f"[DEBUG] Email sent successfully.")
167
  return True
168
  except Exception as e:
169
+ print(f"[DEBUG] Network/SMTP EXCEPTION: {e}")
170
+ print(f"[!] Failed to send email: {e}")
171
  return False
172
 
173
  def send_event_alerts(events):
 
189
 
190
  msg += (
191
  f"<b>{ev.get('event_code', '-')} - "
192
+ f"{ev.get('event_name', 'Unknown')}</b><br><br>"
193
+ f"{ev.get('event_category', '-')}<br><br>"
194
+ f"{start} to {end}<br><br>"
195
+ f"{ev.get('location', '-')}<br><br>"
196
+ f"{ev.get('status', '-')}<br><br>"
197
  f"Seats: Max {ev.get('maximum_count', '-')} | "
198
+ f"Applied {ev.get('applied_count', '-')}<br>"
199
+ f"<a href='{ev.get('web_url', '#')}'>View Event Here</a><br>"
200
+ f"<hr>"
201
  )
202
+ send_email_message("📢 New BIP Event(s) Found!", msg, is_html=True)
203
 
204
 
205
  # ==============================================================================
 
305
 
306
  if err:
307
  print(f"{time_str.lower()} - ❌ Error scraping events: {err}")
308
+ send_email_message(
309
+ "⚠️ BIP Scraper Error",
310
+ "⚠️ <b>Scraper Error!</b><br><br>"
311
+ f"The notifier encountered an error and has paused checking. Error:<br>"
312
+ f"<code>{err}</code><br><br>"
313
+ "Please send an email to this address with the subject <b>BIP_COOKIES</b> and your new cookies in the body like this:<br><br>"
314
+ "<code>XSRF_TOKEN=your_new_token_here<br>BIP_SESSION=your_new_session_here</code>",
315
+ is_html=True
316
  )
317
  SESSION_EXPIRED = True
318
  EXPIRED_XSRF = xsrf
 
391
  print(f"Link: {ev.get('web_url')}")
392
  print("-" * 60)
393
 
394
+ def test_email_alert():
395
+ """Sends a dummy test message to the configured Email."""
396
+ print("Sending test exact alert to Email...")
397
+ success = send_email_message("🤖 Test Alert", "🤖 <b>Test Alert from BIP CLI Notifier</b><br><br>Your Email integration is working perfectly!", is_html=True)
398
  if success:
399
  print("✅ Test message sent successfully!")
400
  else:
 
414
  target_time = time.time() + CHECK_INTERVAL_SECONDS
415
 
416
  while time.time() < target_time:
417
+ cookies_updated = check_email_for_cookies()
418
  if cookies_updated:
419
  # User sent new cookies, immediately break to run process_tick right now!
420
  break
 
451
  parser = argparse.ArgumentParser(description="BIP Cloud Notifier CLI")
452
  parser.add_argument("--list-all", action="store_true", help="List all recent events and exit")
453
  parser.add_argument("--latest", action="store_true", help="Print details of the latest event and exit")
454
+ parser.add_argument("--test-alert", action="store_true", help="Send a test message to Email and exit")
455
  parser.add_argument("--run", action="store_true", help="Start the continuous 1-minute monitoring loop")
456
  print("Parsed arguments:", parser.parse_args())
457
  args = parser.parse_args()
 
461
  elif args.latest:
462
  get_latest_event()
463
  elif args.test_alert:
464
+ test_email_alert()
465
  elif args.run:
466
  threading.Thread(target=run_dummy_server, daemon=True).start()
467
  start_loop()