forked from shvekyha/myVisitCrawler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmyVisitCrawler.user.js
159 lines (123 loc) · 5.5 KB
/
myVisitCrawler.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// ==UserScript==
// @name My Visit Crawler
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Search for a free passport renewal appointment
// @author Hadas Shveky-Teman
// @match https://myvisit.com
// @grant none
// @run-at document-idle
// ==/UserScript==
// ------ USER DATA -----
const ID = 'XXXXXXXXX'; //The ID of the person requesting the appointment
const PHONE_NUMBER = 'XXXXXXXXXX'; //The phone number of the person requesting the appointment
const LOCATION_NUM_TO_CHECK = 20; //Number of locations to scan
const LOCATION_SKIP_LIST = []; //List of locations indexes to skip (0-based) - for example [13,20]
const MONTHS_SKIP_LIST = ['Aug','Jul']; //List of months to skip when looking for an appointment
//-----------------------
const sleep = (milliseconds) => {
return new Promise(resolve => {
setTimeout(resolve, milliseconds);
});
}
const waitForElement = async (elementSelector, numOfTrials) => {
let trials = 0
while (!document.querySelector(elementSelector)){
if (numOfTrials && trials >= numOfTrials) break;
trials++
await sleep(1000);
}
console.log('found ',elementSelector);
}
const searchSpot = async (id, phoneNum) => {
const SERVICE_INDEX = 0;
const START_FROM_LOCATION = 0;
//goverment services
document.querySelectorAll('li.icon-button-hvr-shrink')[2].click();
await waitForElement('li.provider-tile');
//interior office
document.querySelectorAll('li.provider-tile')[SERVICE_INDEX].click();
await waitForElement('input#ID_KEYPAD');
//fill up id
const idInput = document.querySelector('input#ID_KEYPAD');
let idLastValue = idInput.value;
idInput.value = id;
let idEvent = new Event("input", { bubbles: true });
idEvent.simulated = true;
// hack React16/Angular
let idTracker = idInput._valueTracker;
if (idTracker) {
idTracker.setValue(idLastValue);
}
idInput.dispatchEvent(idEvent);
//continue btn
document.querySelector('button.actionButton').click();
await waitForElement('input#PHONE_KEYPAD');
//fill up phone number
const phoneInput = document.querySelector('input#PHONE_KEYPAD');
let phoneLastValue = phoneInput.value;
phoneInput.value = phoneNum;
let phoneEvent = new Event("input", { bubbles: true });
phoneEvent.simulated = true;
// hack React16/Angular
let phoneTracker = phoneInput._valueTracker;
if (phoneTracker) {
phoneTracker.setValue(phoneLastValue);
}
phoneInput.dispatchEvent(phoneEvent);
//continue btn
document.querySelector('button.actionButton').click();
await waitForElement('div.list-item-body');
//biometric documentation
document.querySelectorAll('div.list-item-body')[0].click();
await waitForElement('div.list-item-body.with-2icons');
for (let index=START_FROM_LOCATION; index<LOCATION_NUM_TO_CHECK; index++){
//get location
const locationDiv = document.querySelectorAll('div.list-item-body.with-2icons')[index]
const locationName = locationDiv.querySelector('div span').innerText
//some locations are for locals only, need to skip them
if (LOCATION_SKIP_LIST.includes(index)){
console.log(`*** Skipping location ${locationName}`);
continue;
}
locationDiv.click();
await waitForElement('li.list-item > button');
await sleep(4000);
//biometric passport
document.querySelector('li.list-item > button').click();
await waitForElement('li.radioButton-container');
//biometric passport renew
document.querySelectorAll('li.radioButton-container')[2].click();
//waiting for 'Available Dates' title
await waitForElement('div.picker-title-content.ng-binding');
//waiting for 'Not Available Dates' title
await waitForElement('#mCSB_5_container div span', 5);
const availDay = document.querySelector('li button.calendarDay div.font-medium');
const availMonth = document.querySelectorAll('li button.calendarDay div.font-medium')[1];
const availDate = document.querySelector('li button.calendarDay div.font-xlarge');
if (availMonth && !MONTHS_SKIP_LIST.includes(availMonth.innerText)){
console.log(`*** Found an open spot in ${locationName} at ${availDay.innerText} ${availDate.innerText} ${availMonth.innerText}`);
const stop = confirm(`Found a spot!\nIn ${locationName} \nAt ${availDay.innerText} ${availDate.innerText} ${availMonth.innerText}\n\nWould you like to book it?\n\nIf yes, click OK and book manually, to continue searching click Cancel`)
if (stop){
break;
}
} else {
console.log(`*** No available date found in ${locationName}`);
}
//click on back button
document.querySelector('.appHeaderContent .pull-right.ng-isolate-scope .appHeader-button button').click();
await sleep(8000);
}
}
window.addEventListener('load', async function(){
const BTN_PLACEMENT_SELECTOR = '.appHeader';
let btn = document.createElement('button');
btn.innerHTML = 'Find my spot!';
btn.style = 'margin-left: 20px; position:relative;'
btn.onclick = () => searchSpot(ID, PHONE_NUMBER);
await waitForElement('li.icon-button-hvr-shrink');
setTimeout(() => {
let div = document.querySelector(BTN_PLACEMENT_SELECTOR);
div.appendChild(btn);
},2000);
});