Update cowin.py

This commit is contained in:
roShan 2021-06-02 14:55:47 +05:30 committed by GitHub
parent 742582b5f2
commit a4cb3c239f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

194
cowin.py
View file

@ -1,50 +1,57 @@
from apscheduler.schedulers.blocking import BlockingScheduler try:
from bs4 import BeautifulSoup import schedule
from datetime import datetime from bs4 import BeautifulSoup
import subprocess from datetime import datetime
import requests import subprocess
import hashlib import requests
import base64 import hashlib
import time import base64
import json import time
import fire import json
import sys import fire
import re import sys
import os import re
import os
except ImportError:
print("First run requirements instaling command")
print("pip install -r requirements.txt")
exit()
OTP_SITE_URL = None OTP_SITE_URL = None
OTP_VALID_DURATION_SECONDS = 180 OTP_VALID_DURATION_SECONDS = 180
''' '''
Add Worker Domain here example : https://db.domain.workers.dev Add Worker Domain here in Double Quore example : "https://db.domain.workers.dev"
Check this : https://github.com/truroshan/CloudflareCoWinDB Check this : https://github.com/truroshan/CloudflareCoWinDB
''' '''
scheduler = BlockingScheduler() # scheduler = BlockingScheduler()
def line_break(): print("-"*25) def line_break(): print("-"*25)
def clear_screen(): os.system("clear") def clear_screen(): os.system('clear' if os.name =='posix' else 'cls')
class CoWinBook(): class CoWinBook():
def init( def init(
self, self,
mobile_no, mobile_no, # --m
pin = "Not Passed", pin = "Not Passed", # --p
age = 18 , age = 18 , # --a
vaccine = "ANY", vaccine = "ANY", # --v
dose = 1, dose = 1, # --d
otp = 'a', otp = 'a', # --o
time = 30, time = 30, # --t
bookToday = 1, bookToday = 1, # --b
relogin = None ): fee_type = "BOTH", # --f
relogin = None # --r
):
self.mobile_no = str(mobile_no) self.mobile_no = str(mobile_no)
if relogin and os.path.exists(self.mobile_no): os.remove(self.mobile_no) if relogin and os.path.exists(self.mobile_no): os.remove(self.mobile_no)
# Cron Time # Cron Time
global TIME global TIME
TIME = time TIME = 8 if time < 10 else time
# Include today session for Booking Slot # Include today session for Booking Slot
self.bookToday = 0 if bookToday is True else 1 self.bookToday = 0 if bookToday is True else 1
@ -55,6 +62,7 @@ class CoWinBook():
# Vaccination Center id and Session id for Slot Booking # Vaccination Center id and Session id for Slot Booking
self.vaccine = vaccine.upper() self.vaccine = vaccine.upper()
self.vacc_fee_type = fee_type.upper()
self.vacc_center = None self.vacc_center = None
self.vacc_session = None self.vacc_session = None
self.slot_time = None self.slot_time = None
@ -96,7 +104,7 @@ class CoWinBook():
bottomBanner = "for Today and Day After 📆 ..." if self.bookToday == 0 else "for Tomorrow and Day After 📆 ..." bottomBanner = "for Today and Day After 📆 ..." if self.bookToday == 0 else "for Tomorrow and Day After 📆 ..."
print(f" 📍 {self.pin} 💉 {age}+ ⌛️ {TIME} Seconds") print(f" 📍 {self.pin} 💉 {age}+ ⌛️ {TIME} Seconds")
print(f" 📲 xxxx{self.mobile_no[7:]} 💉 {self.vaccine} (Dose :{self.dose})") print(f" 📲 XXXX{self.mobile_no[7:]} 💉 {self.vaccine} (Dose :{self.dose})")
print(f"CoWin Auto Slot Booking 🔃\n{bottomBanner}") print(f"CoWin Auto Slot Booking 🔃\n{bottomBanner}")
line_break() line_break()
@ -138,12 +146,16 @@ class CoWinBook():
def checkToken(self): def checkToken(self):
# Pause job of Checking Slot # Pause job of Checking Slot
scheduler.pause_job('slot') # scheduler.pause_job('slot')
self.getSession() response = self.fetch_beneficiaries()
try:
response.json()
except json.decoder.JSONDecodeError:
self.login_cowin()
# Resume job of Checking Slot # Resume job of Checking Slot
scheduler.resume_job('slot') # scheduler.resume_job('slot')
# Login to selfregistration.cowin.gov.in/ # Login to selfregistration.cowin.gov.in/
def login_cowin(self): def login_cowin(self):
@ -155,11 +167,14 @@ class CoWinBook():
response = self.session.post('https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP',data=self.get_data()) response = self.session.post('https://cdn-api.co-vin.in/api/v2/auth/generateMobileOTP',data=self.get_data())
if self.otp == 's': requests.delete(f"{OTP_SITE_URL}/{self.mobile_no}") if self.otp == 's' and OTP_SITE_URL is not None: requests.delete(f"{OTP_SITE_URL}/{self.mobile_no}")
otpSha265 = self.get_otp() otpSha265 = self.get_otp()
try:
txn_id = response.json()['txnId'] txn_id = response.json()['txnId']
except json.decoder.JSONDecodeError:
print("Wrong OTP Entered")
return
self.data = { self.data = {
"otp":otpSha265, "otp":otpSha265,
@ -180,11 +195,11 @@ class CoWinBook():
otp_fetching_mode = "" otp_fetching_mode = ""
if self.otp == 'a': if self.otp == 'a':
otp_fetching_mode = 'AutoMode' otp_fetching_mode = 'Auto Mode'
elif self.otp == 's': elif self.otp == 's':
otp_fetching_mode = 'SiteMode' otp_fetching_mode = 'Site Mode'
else: else:
otp_fetching_mode = "ManualMode" otp_fetching_mode = "Manual Mode"
print(f"OTP Sent ({otp_fetching_mode}) 📲 ... ") print(f"OTP Sent ({otp_fetching_mode}) 📲 ... ")
@ -200,9 +215,9 @@ class CoWinBook():
last_msg_body = last_msg.get("body",'') last_msg_body = last_msg.get("body",'')
print(f'Waiting for OTP {i} sec') print(f'Waiting for OTP {i} sec')
sys.stdout.write("\033[F") self.set_cursor()
d1 = datetime.strptime(last_msg.get("received"), '%Y-%m-%d %H:%M:%S') d1 = datetime.strptime(last_msg.get("received","2019-12-01 09:09:09"), '%Y-%m-%d %H:%M:%S')
d2 = datetime.now() # current date and time d2 = datetime.now() # current date and time
diff = (d2 - d1).total_seconds() diff = (d2 - d1).total_seconds()
if (curr_msg_body != last_msg_body and "cowin" in last_msg_body.lower()) or diff <= OTP_VALID_DURATION_SECONDS: if (curr_msg_body != last_msg_body and "cowin" in last_msg_body.lower()) or diff <= OTP_VALID_DURATION_SECONDS:
@ -233,14 +248,15 @@ class CoWinBook():
msg = json.loads(msg)[0] msg = json.loads(msg)[0]
return msg return msg
except KeyError: except KeyError:
raise Exception("Install Termux:API 0.31 Version for AutoMode ") raise Exception("Install Termux:API from FDroid for Auto Mode ")
# Get OTP using DB hosted on Cloudflare and Attached with https://play.google.com/store/apps/details?id=com.gawk.smsforwarder
# Get OTP using DB hosted on Cloudflare and Configure with https://play.google.com/store/apps/details?id=com.gawk.smsforwarder
elif self.otp == 's': elif self.otp == 's':
if OTP_SITE_URL is None: if OTP_SITE_URL is None:
raise Exception("First Setup DB on Cloudflare \nhttps://github.com/truroshan/CloudflareCoWinDB ") raise Exception("First Setup DB on Cloudflare \nhttps://github.com/truroshan/CloudflareCoWinDB ")
res = requests.get(f"{OTP_SITE_URL}/{self.mobile_no}",timeout=3).json() res = requests.get(f"{OTP_SITE_URL}/{self.mobile_no}").json()
if res.get("status"): if res.get("status"):
msg['body'] = res.get('data').get("message") msg['body'] = res.get('data').get("message")
@ -262,12 +278,7 @@ class CoWinBook():
self.requestStatus = response.status_code self.requestStatus = response.status_code
if response.status_code == 200: if response.status_code == 200:
# CoWIN server may respond back with HTTP 204 so response.ok
# will not be right to depend upon. The content will be empty
# and so it will crash if we try to get the JSON body.
self.check_slot(response.json()) self.check_slot(response.json())
elif response.ok: # We have received ok response but without content
self.request_slot()
elif response.status_code == 401: elif response.status_code == 401:
print("Re-login Account : " + datetime.now().strftime("%H:%M:%S") + " 🤳") print("Re-login Account : " + datetime.now().strftime("%H:%M:%S") + " 🤳")
self.checkToken() self.checkToken()
@ -276,7 +287,8 @@ class CoWinBook():
# Check Slot availability # Check Slot availability
def check_slot(self,response): def check_slot(self,response):
for center in response.get('centers',[]): centers = response.get('centers',[])
for center in centers:
for session in center.get('sessions')[self.bookToday:]: for session in center.get('sessions')[self.bookToday:]:
@ -287,12 +299,13 @@ class CoWinBook():
capacity = session.get(f'available_capacity_dose{self.dose}') capacity = session.get(f'available_capacity_dose{self.dose}')
session_date = session.get('date') session_date = session.get('date')
vaccine_name = session.get('vaccine') + "ANY" vaccine_name = session.get('vaccine')
if capacity > 1 and \ if capacity > 1 and \
self.vaccine in vaccine_name and \ (self.vaccine in vaccine_name or self.vaccine == "ANY") and \
session.get('min_age_limit') == self.age and \ session.get('min_age_limit') == self.age and \
center.get('center_id') in self.center_id: center.get('center_id') in self.center_id:
self.slot_time = session.get('slots')[0] self.slot_time = session.get('slots')[0]
MSG = f'💉 {capacity} #{vaccine_name} / {session_date} / {center_name} 📍{self.pin}' MSG = f'💉 {capacity} #{vaccine_name} / {session_date} / {center_name} 📍{self.pin}'
@ -302,13 +315,13 @@ class CoWinBook():
BOOKED = self.book_slot() BOOKED = self.book_slot()
if BOOKED: if BOOKED:
scheduler.shutdown(wait=False) # scheduler.shutdown(wait=False)
print("Shutting Down CoWin Script 👩‍💻 ") print("Shutting Down CoWin Script 👩‍💻 ")
return exit()
# When last Checked # When last Checked
print(f"Last Checked ✅ : " + datetime.now().strftime("%H:%M:%S") + " 🕐") print(f"Last Checked {self.requestStatus} ✅ : " + datetime.now().strftime("%H:%M:%S") + " 🕐")
sys.stdout.write("\033[F") self.set_cursor()
# Get Solved Captcha in String # Get Solved Captcha in String
def get_captcha(self): def get_captcha(self):
@ -373,6 +386,8 @@ class CoWinBook():
return True return True
elif status == 409: elif status == 409:
print("This vaccination center is completely booked for the selected date 😥") print("This vaccination center is completely booked for the selected date 😥")
elif status == 400:
print("Minimum age criteria is 45 years for this center")
elif status == 401: elif status == 401:
self.login_cowin() self.login_cowin()
self.book_slot() self.book_slot()
@ -430,31 +445,48 @@ class CoWinBook():
def select_center(self): def select_center(self):
response = self.fetch_center() response = self.fetch_center()
# CoWIN server may respond back with HTTP 204 so response.ok
# will not be right to depend upon. The content will be empty
# and so it will crash if we try to get the JSON body.
while response.status_code != 200: while response.status_code != 200:
print(f'Trying to fetch center detail. Please wait...') print(f'Trying to fetch center detail. Please wait...')
sys.stdout.write("\033[F") self.set_cursor()
time.sleep(1) time.sleep(5)
response = self.fetch_center() response = self.fetch_center()
clear_screen()
response = response.json() response = response.json()
CENTERS = {} CENTERS = {}
INDEX_S = [] INDEX_S = []
if not response.get('centers'):
print("No Centers Available at this location")
print("Shutting Down CoWin Script 👩‍💻 ")
exit()
print(f"Select Vaccination Center ({self.pin}) 💉 \n") print(f"Select Vaccination Center ({self.pin}) 💉 \n")
counter = 1 counter = 1
for center in response.get('centers',[]): for center in response.get('centers',[]):
vaccine_fee_type = center.get("fee_type").upper()
vaccine__fee_emoji = '🆓' if "FREE" in vaccine_fee_type else '💰'
for session in center.get('sessions'): for session in center.get('sessions'):
if session.get('min_age_limit') == self.age: vaccine_name = session.get("vaccine")
print(f'{counter} : {center.get("name")}')
if session.get('min_age_limit') == self.age \
and (self.vaccine in vaccine_name or self.vaccine == 'ANY') \
and (self.vacc_fee_type in vaccine_fee_type or self.vacc_fee_type == "BOTH" ):
print(f'{counter} : {center.get("name")} {vaccine__fee_emoji}')
CENTERS[counter] = center.get('center_id') CENTERS[counter] = center.get('center_id')
INDEX_S.append(counter) INDEX_S.append(counter)
counter += 1 counter += 1
break break
if counter == 1:
# clear_screen()
print(f"No Center available Vaccine : ( 💉{self.vaccine}) Fee Type : ({self.vacc_fee_type}).")
self.shutting_down()
exit()
print() print()
line_break() line_break()
@ -464,7 +496,10 @@ class CoWinBook():
* Select Mutiple with Space * Select Mutiple with Space
input : 1 2 3 4 input : 1 2 3 4
* Select All Center * Select All Center
Hit Enter without Input\n""") Hit Enter without Input
**pass --f paid or free
**pass --v vacc_name \n""")
line_break() line_break()
@ -490,7 +525,7 @@ class CoWinBook():
response = self.fetch_beneficiaries() response = self.fetch_beneficiaries()
while response.status_code != 200: while response.status_code != 200:
print(f'Please wait...') print(f'Please wait...')
sys.stdout.write("\033[F") self.set_cursor()
time.sleep(5) time.sleep(5)
response = self.fetch_beneficiaries() response = self.fetch_beneficiaries()
@ -502,8 +537,8 @@ class CoWinBook():
print(f"Select User for Vaccination 👩‍👦‍👦 \n") print(f"Select User for Vaccination 👩‍👦‍👦 \n")
if not response.get('beneficiaries',[]): if not response.get('beneficiaries',[]):
print("No user added in beneficiaries") print("No beneficiaries added in Account")
return exit()
counter = 1 counter = 1
for user in response.get('beneficiaries'): for user in response.get('beneficiaries'):
@ -513,6 +548,13 @@ class CoWinBook():
INDEX_S.append(counter) INDEX_S.append(counter)
counter += 1 counter += 1
if counter == 1:
# clear_screen()
print(f"No beneficiaries available for Dose {self.dose}.")
self.shutting_down()
exit()
print() print()
line_break() line_break()
print(""" print("""
@ -539,6 +581,12 @@ class CoWinBook():
self.user_id = USER_ID self.user_id = USER_ID
def shutting_down(self):
print("Shutting Down CoWin Script 👩‍💻 ")
def set_cursor(self):
sys.stdout.write("\033[F")
if __name__ == '__main__': if __name__ == '__main__':
@ -549,9 +597,15 @@ if __name__ == '__main__':
fire.Fire(cowin.init) fire.Fire(cowin.init)
# Check for Slot # Check for Slot
scheduler.add_job(cowin.book_now, 'interval',id = "slot",seconds = TIME, misfire_grace_time=2) # scheduler.add_job(cowin.book_now, 'interval',id = "slot",seconds = TIME, misfire_grace_time=2,replace_existing=True)
schedule.every(TIME).seconds.do(cowin.book_now)
# Check Token every 3 min # Check Token every 3 min
scheduler.add_job(cowin.checkToken, 'cron',id ="login", minute = f'*/3',misfire_grace_time= 30) # scheduler.add_job(cowin.checkToken, 'cron',id ="login", minute = f'*/3',misfire_grace_time= 30)
schedule.every(3).minutes.do(cowin.checkToken)
scheduler.start() # scheduler.start()
while True:
schedule.run_pending()
time.sleep(1)