Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update repo to work with latest checkvisaslot screenshots #2

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,5 @@ dmypy.json
# Cython debug symbols
cython_debug/

.history
.space
21 changes: 21 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
opencv-python-headless = "~=4.5.5.64"
numpy = "~=1.21.6"
pytesseract = "~=0.3.9"
requests = "~=2.27.1"
python-dotenv = "~=0.20.0"
python-telegram-bot = "~=13.11"
python-dateutil = "*"
datefinder = "*"
dateparser = "*"
thefuzz = {extras = ["speedup"], version = "*"}

[dev-packages]

[requires]
python_version = "3.8"
679 changes: 679 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ DevTools Networks tab + Python + Tesseract + 🧠 = 💣

## Usage 👨‍💻

- Clone and create heroku app linked to this.
- Add [apt buildpack](https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-apt) (we need to install `libgl1`
to make cv2 work).
- `heroku config:set TESSDATA_PREFIX=/app/.apt/usr/share/tesseract-ocr/tessdata`
- Clone repo
- install pipenv
- install tesseract ocr for your machine
- Setup config vars of
- `API_KEY`: From your https://checkvisaslots.com.
- `BOT_TOKEN`: From BotFather in Telegram.
- `CHAT_ID`: ID of group you want to run it in.
- `YEAR`: which year you're looking for slots in
- `MONTHS`: which months to notify you for
- Change the location (default Chennai) and checking interval (default 10 mins).
- run `pipenv install`
- run `pipenv run python bot.py`

Some info on using the bot.
- Monitoring start immediately - runs once every 10 mins.
Expand Down
88 changes: 53 additions & 35 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import traceback
from datetime import datetime, timedelta
from urllib.request import urlopen
from urllib.parse import quote
import re

import cv2
import numpy as np
Expand All @@ -12,6 +14,7 @@
from dotenv import dotenv_values
from telegram import ParseMode, Update
from telegram.ext import CallbackContext, CommandHandler, Updater
from thefuzz import fuzz, process

SLOTS_URL = "https://app.checkvisaslots.com/slots/v1"
SCREENSHOTS_URL = "https://app.checkvisaslots.com/retrieve/v1"
Expand All @@ -21,6 +24,8 @@
CHAT_ID = dotenv_values("config.env").get("CHAT_ID")
BOT_TOKEN = dotenv_values("config.env").get("BOT_TOKEN")
SEND_DUPES = eval(dotenv_values("config.env").get("SEND_DUPES"))
YEAR = dotenv_values("config.env").get("YEAR")
MONTHS = dotenv_values("config.env").get("MONTHS").split(',')

logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO)
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -55,12 +60,12 @@ def image_to_bytes(img):
return bts


def check_chennai_consulate(results):
return [[each["slots"], each["createdon"]] for each in results if each["visa_location"] == "CHENNAI"][0]
def check_NEWDELHI_consulate(results):
return [[each["slots"], each["createdon"]] for each in results['slotDetails'] if each["visa_location"] == "NEW DELHI VAC"][0]


def get_chennai_screenshots(results):
screenshot_urls = [(each["img_url"], each["createdon"]) for each in results if "CHENNAI" in each["img_url"]]
def get_NEWDELHI_screenshots(results):
screenshot_urls = [(each["img_url"], each["createdon"]) for each in results if quote("NEW DELHI VAC") in each["img_url"]]
screenshots = []
for url, timestamp in screenshot_urls:
screenshots.append([url_to_image(SCREENSHOTS_FILE_URL + url), timestamp])
Expand All @@ -76,36 +81,49 @@ def run_once(bot, chat_id, old_log_text=None, old_log_pics=None, api_key=None, s
old_log_pics = []
if api_key is None:
api_key = random.choice(API_KEYS)
response = requests.get(SLOTS_URL, headers=get_slot_header(api_key))
results = eval(response.text)
slots = check_chennai_consulate(results)

gmt_time = datetime.strptime(slots[1], "%a, %d %b %Y %H:%M:%S %Z")
ist_time = gmt_to_ist(gmt_time)
log_text = f'{slots[0]} slots available at {datetime.strftime(ist_time, "%I:%M:%S %p")}'
# commenting this request because we're making double calls to api and exhausting api calls faster(1st is this call, 2nd being screenshot call)
# response = requests.get(SLOTS_URL, headers=get_slot_header(api_key))
# mockRespText = '{"slotDetails":[{"img_id":7602746,"visa_location":"CHENNAI","slots":0,"createdon":"Sat, 29 Apr 2023 17:10:46 GMT"},{"img_id":7602836,"visa_location":"CHENNAI VAC","slots":1,"createdon":"Sat, 29 Apr 2023 17:21:03 GMT"},{"img_id":7602748,"visa_location":"HYDERABAD","slots":0,"createdon":"Sat, 29 Apr 2023 17:10:49 GMT"},{"img_id":7602839,"visa_location":"HYDERABAD VAC","slots":6,"createdon":"Sat, 29 Apr 2023 17:21:11 GMT"},{"img_id":7602640,"visa_location":"KOLKATA","slots":0,"createdon":"Sat, 29 Apr 2023 16:58:24 GMT"},{"img_id":7602785,"visa_location":"KOLKATA VAC","slots":4,"createdon":"Sat, 29 Apr 2023 17:17:35 GMT"},{"img_id":7602765,"visa_location":"MUMBAI","slots":0,"createdon":"Sat, 29 Apr 2023 17:14:19 GMT"},{"img_id":7602830,"visa_location":"MUMBAI VAC","slots":30,"createdon":"Sat, 29 Apr 2023 17:20:48 GMT"},{"img_id":7602766,"visa_location":"NEW DELHI","slots":0,"createdon":"Sat, 29 Apr 2023 17:14:22 GMT"},{"img_id":7602831,"visa_location":"NEW DELHI VAC","slots":6,"createdon":"Sat, 29 Apr 2023 17:20:49 GMT"}],"userDetails":{"visa_type":"B1/B2","appointment_type":"Regular","subscription":"FREE"}}\n'
# results = eval(mockRespText)
# results = eval(response.text)
# slots = check_NEWDELHI_consulate(results)

# gmt_time = datetime.strptime(slots[1], "%a, %d %b %Y %H:%M:%S %Z")
# ist_time = gmt_to_ist(gmt_time)
# log_text = f'{slots[0]} slots available at {datetime.strftime(ist_time, "%I:%M:%S %p")}'
log_text = "running now"
logger.info(log_text)
if send_dupes or log_text != old_log_text:
if slots[0] > 0:
bot.send_message(chat_id=chat_id, text=f"🤯🤯🤯 {log_text} ({api_key}) @Syzygianinfern0 @M_N_Sathish")
else:
bot.send_message(chat_id=chat_id, text=f"{log_text} ({api_key})")
# if send_dupes or log_text != old_log_text:
# if slots[0] > 0:
# bot.send_message(chat_id=chat_id, text=f"🤯🤯🤯 {log_text} ({api_key}) ")
# else:
# bot.send_message(chat_id=chat_id, text=f"{log_text} ({api_key})")
log_pics = []
if slots[0] > 0:
response = requests.get(SCREENSHOTS_URL, headers=get_screenshots_header(api_key))
results = eval(response.text)
screenshots = get_chennai_screenshots(results)
for screenshot, timestamp in screenshots:
text = pytesseract.image_to_string(screenshot)
if "consular" in text.lower():
gmt_time = datetime.strptime(timestamp, "%a, %d %b %Y %H:%M:%S %Z")
ist_time = gmt_to_ist(gmt_time)
if send_dupes or not any(np.array_equal(screenshot, each) for each in old_log_pics):
bot.send_photo(
chat_id=chat_id,
photo=image_to_bytes(screenshot),
caption=datetime.strftime(ist_time, "%I:%M:%S %p") + " @Syzygianinfern0 @M_N_Sathish",
)
log_pics.append(screenshot)
# if slots[0] > 0:
response = requests.get(SCREENSHOTS_URL, headers=get_screenshots_header(api_key))
results = eval(response.text)
screenshots = get_NEWDELHI_screenshots(results)
for screenshot, timestamp in screenshots:
text = pytesseract.image_to_string(screenshot)
# if "consular" in text.lower():

# remove line with 'current appointment' in it
fuzzyMatch = process.extractOne('current appointment', text.splitlines(), scorer=fuzz.partial_ratio)
matchThreshold = 80
if fuzzyMatch is not None and fuzzyMatch[1] > matchThreshold:
text = ''.join(text.split(fuzzyMatch[0]))
if YEAR in text.lower() and len([month for month in MONTHS if month.lower() in text.lower()]) > 0:
text_with_dates = [re.sub(r"[^a-zA-Z0-9 ]", "", line) for line in text.splitlines() if YEAR in line]
gmt_time = datetime.strptime(timestamp, "%a, %d %b %Y %H:%M:%S %Z")
ist_time = gmt_to_ist(gmt_time)
if send_dupes or not any(np.array_equal(screenshot, each) for each in old_log_pics):
bot.send_message(chat_id=CHAT_ID, text="<b>"+'\n\n'.join(text_with_dates)+"</b>", parse_mode=ParseMode.HTML)
bot.send_photo(
chat_id=chat_id,
photo=image_to_bytes(screenshot),
caption=datetime.strftime(ist_time, "%I:%M:%S %p") + "",
)
log_pics.append(screenshot)

return log_text, log_pics

Expand All @@ -121,7 +139,7 @@ def monitor(bot, chat_id, old_log_text=None, old_log_pics=None):
minutes = 5
except Exception as e:
logger.error(e)
bot.send_message(chat_id=CHAT_ID, text=f"Bot Crashed @Syzygianinfern0: {e}\n{traceback.format_exc()}")
bot.send_message(chat_id=CHAT_ID, text=f"Bot Crashed : {e}\n{traceback.format_exc()}")
log_text, log_pics = old_log_text, old_log_pics
minutes = 1

Expand Down Expand Up @@ -151,7 +169,7 @@ def run_once_handler(update: Update, context: CallbackContext):
except Exception as e:
logger.error(e)
context.bot.send_message(
chat_id=update.effective_chat.id, text=f"Bot Crashed @Syzygianinfern0: {e}\n{traceback.format_exc()}"
chat_id=update.effective_chat.id, text=f"Bot Crashed : {e}\n{traceback.format_exc()}"
)
else:
context.bot.send_message(chat_id=update.effective_chat.id, text="Unauthorized!")
Expand All @@ -165,7 +183,7 @@ def main():

# Welcome message
bot.send_message(
chat_id=CHAT_ID, text="<b>Bot Started!</b> @Syzygianinfern0 @M_N_Sathish", parse_mode=ParseMode.HTML
chat_id=CHAT_ID, text="<b>Bot Started!</b>", parse_mode=ParseMode.HTML
)
logger.info("Bot started!")

Expand Down
3 changes: 3 additions & 0 deletions config.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
API_KEY=<FILL ME>
CHAT_ID=<FILL ME>
BOT_TOKEN=<FILL ME>
SEND_DUPES=True
YEAR=2023
MONTHS=may,june,july,august