rozierguillaume / vitemadose

20 stars 7 forks source link

Are you interested in a "VMD watcher" ? #47729

Open mdussere opened 3 years ago

mdussere commented 3 years ago

Hi,

I wrote a simple watcher on VMD results to pop when some appointments are available in my department. And it worked for me pretty well (thank you for your hard work :-) ) Are you interested in the piece of code ?

Regards

Michael

import logging
import sys
import time
import webbrowser
import requests

LOGGER = logging.getLogger('Auto VMD')
log_format = '%(asctime)s %(levelname)s %(filename)s:%(lineno)d %(message)s'
logging.basicConfig(stream=sys.stdout, level=logging.INFO, format=log_format)

class VMDWatcher:

    URL_PATTERN = 'https://vitemadose.gitlab.io/vitemadose/{}.json'

    def __init__(self, departement: int = 31, vaccine_type: str = 'Pfizer-BioNTech',
                 min_appointment_count: int = 1, appointment_schedules: str = '7_days',
                 watch_delay=30):

        self.departement = departement
        self.vaccine_type = vaccine_type
        self.min_appointment_count = min_appointment_count
        self.appointment_delay = appointment_schedules
        self.watch_delay = watch_delay
        self.last_open_url = None

    def get_all_appointments(self):

        url = VMDWatcher.URL_PATTERN.format(self.departement)
        response = requests.get(url)

        appointments = []
        if response.status_code == 200:
            raw_json = response.json()
            if 'centres_disponibles' in raw_json:
                appointments = raw_json['centres_disponibles']

        else:
            LOGGER.warning(f'Failed to get response from {url}')

        return appointments

    def get_valid_appointments(self):

        appointments = self.get_all_appointments()

        valid_apointments = [x for x in appointments if self.is_valid(x)]
        valid_apointments = sorted(valid_apointments, key=lambda x: self.get_appointment_count(x), reverse=True)

        return valid_apointments

    def is_valid(self, appointment):
        appointment_count = self.get_appointment_count(appointment)
        has_vaccine_type = 'vaccine_type' in appointment and appointment['vaccine_type'] \
                           and self.vaccine_type in appointment['vaccine_type']
        has_url = not appointment['appointment_by_phone_only'] and   appointment['url']
        return  has_url and has_vaccine_type and appointment_count >= self.min_appointment_count

    def get_appointment_count(self, appointment):
        if self.appointment_delay and 'appointment_schedules' in appointment and appointment['appointment_schedules']:
            appointment_count = appointment['appointment_schedules'][self.appointment_delay]
        else:
            appointment_count = appointment['appointment_count']

        return appointment_count

    def open_first_appointment(self, appointments):

        if appointments:
            appointment_url = appointments[0]['url']
            nb_appointments = self.get_appointment_count(appointments[0])
            if appointment_url != self.last_open_url:
                LOGGER.info(f'Quick take me to the available {nb_appointments} appointments ({appointment_url})!!!')
                webbrowser.open(appointment_url)
                self.last_open_url = appointment_url
            else:
                LOGGER.info(f'still the same appointments')
        else:
            LOGGER.info('no appointment available so far')
            self.last_open_url = None

    def watch(self):
        nb_watch = 1
        while True:
            LOGGER.info(f'Attempt {nb_watch} to find an appointment (departement = {self.departement}) ...')
            appointments = watcher.get_valid_appointments()
            watcher.open_first_appointment(appointments)

            nb_watch += 1
            time.sleep(self.watch_delay)

if __name__ == '__main__':

    watcher = VMDWatcher()
    watcher.watch()

    LOGGER.info('fin')
mdussere commented 3 years ago

PS: if you are interested, of course I would add some arg parsing and few comments