// ==UserScript== // @name Agenda Tamponi // @namespace https://andreacassani.com/apps/agenda-tamponi // @version 0.5.10 // @description Miglioramenti per prenotazione di tamponi su progetto SOLE // @author Andrea Cassani // @icon https://i.ibb.co/88kwYf3/icon128.png // @updateURL https://raw.githubusercontent.com/andreacassani/Agenda-Tamponi/main/agendatamponi.meta.js // @downloadURL https://raw.githubusercontent.com/andreacassani/Agenda-Tamponi/main/agendatamponi.user.js // @match https://ws.bolognaausl.progetto-sole.it/soleweb/?wicket:interface* // @match https://www.progetto-sole.it/riservata* // @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js // @grant none // ==/UserScript== (function ($, undefined) { (function () { function prenotazioneTamponi() { let IS_PARSED = false; const AGENDE = []; const REQ_RETRY = 3; const BATCH_TIME = 125; const PARSE_RANGE_DAYS = 14; const CODICI_ETA = [ "SCONOSCIUTO", "TUTTE LE ETA", "MAGGIORE 6 ANNI", "MAGGIORE 14 ANNI", "SCUOLE", "PEDIATRICI", "AMBULATORIO BLU", "MONOCLONALI", "MAGGIORE 4 ANNI", ]; const TIPI = { Sconosciuto: "Sconosciuto", Blu: "Ambulatorio Blu", Drive: "Drive Tamponi", Tamponi: "Ambulatorio Tamponi", }; function anticache() { return `${new Date().getTime()}.${Math.random()}`; } function getDate() { const a = new Date(); const b = new Date(); b.setDate(a.getDate() + PARSE_RANGE_DAYS); return { start: Math.round(a.getTime()), end: Math.round(b.getTime()), }; } function sortList(selector, child) { const parent = $(selector); parent .find(child) .sort(function (a, b) { var upA = $(a).text().toUpperCase(); var upB = $(b).text().toUpperCase(); return upA < upB ? -1 : upA > upB ? 1 : 0; }) .appendTo(selector); } function getAppuntamenti(agenda, callback, retry = 0) { const numero = agenda.numero; const nome = agenda.nome; if ($(`#status-agenda-${numero}`).length === 0) { $("#warningText2").append( `

[...] Agenda ${nome}

` ); } try { const interfaces = document.documentElement.innerHTML.match( /\?wicket:interface=:(\d+):(?:nuovaSchedaPanel:)?schedaPanel:formAppuntamento:(\d*):IFormSubmitListener::/ ); const appuntamentoButton = document.documentElement.innerHTML.match( /name="selezionaAppuntamentoButton".+?value="(.+?)"/ ); const formId = document.documentElement.innerHTML.match( /formAppuntamento.+input.+name="(.+?)"/ ); const formData = { [formId[1]]: "", strutturaRicercaAppuntamento: numero, selezionaAppuntamentoButton: appuntamentoButton[1], }; $.ajax({ url: `/soleweb/?wicket:interface=:${interfaces[1]}${ document.documentElement.innerHTML.match(/nuovaSchedaPanel/) ? ":nuovaSchedaPanel" : "" }:schedaPanel:formAppuntamento:${ interfaces[2] }:IFormSubmitListener::`, method: "post", data: formData, timeout: 30000, error: function (_, status) { if (retry > REQ_RETRY) { callback(status, { agenda }); } else { getAppuntamenti(agenda, callback, ++retry); } }, success: function (html) { if (html.match(/login\/wicket:interface/)) { if (retry > REQ_RETRY) { return callback("login_error", { agenda }); } else { return getAppuntamenti(agenda, callback, ++retry); } } if (html.match(/prenotazioneCalendar::IBehaviorListener/)) { const url = html.match( /url: '\?wicket:interface=:(\d+):prenotazioneCalendar::IBehaviorListener:0:&sid=(.+?)',/ ); const wInterface = url[1]; const sid = url[2]; $.ajax({ url: `/soleweb/?wicket:interface=:${wInterface}:prenotazioneCalendar::IBehaviorListener:0:&sid=${sid}&start=${ getDate().start }&end=${ getDate().end }&timezoneOffset=-60&anticache=${anticache()}`, method: "get", dataType: "json", timeout: 30000, error: function (_, status) { if (retry > REQ_RETRY) { callback(status, { agenda }); } else { getAppuntamenti(agenda, callback, ++retry); } }, success: function (json) { if (json[0] && json[0].slot) { let slotHaTempoInRange = false; let indexPrimoSlot = 0; for (let i = 0; i < json.length; i++) { const testDataErogazione = json[i].start; const testOraAppuntamento = new Date( testDataErogazione ).getHours(); if (testOraAppuntamento < 8) { continue; } else { slotHaTempoInRange = true; indexPrimoSlot = i; break; } } if (!slotHaTempoInRange) { return callback("illegal_time", { agenda }); } const descrizioneStruttura = json[indexPrimoSlot].slot.descrizioneStruttura; const dataErogazione = json[indexPrimoSlot].start; const primoAppuntamento = `${new Date( dataErogazione ).getHours()}:${String( new Date(dataErogazione).getMinutes() ).padStart(2, "0")}`; callback(null, { descrizioneStruttura, dataErogazione, primoAppuntamento, agenda, }); } else { callback("no_slot_range", { agenda }); } }, }); } else { callback("no_match", { agenda }); } }, }); } catch (error) { callback(error, { agenda }); } } function parseData(name) { const cleanName = name .toLowerCase() .trim() .replace(/\s\s+/g, " ") .replace(/\s/g, " "); let cat = [cleanName, "Sconosciuto"]; let eta = 0; let rapido = false; if (cleanName.indexOf("covid visita") > -1) { // Ambulatori blu if (cleanName.indexOf("orsola") > -1) { cat = ["Policlinico S. Orsola", "Blu"]; } if (cleanName.indexOf("budrio") > -1) { cat = ["Ospedale di Budrio", "Blu"]; } if (cleanName.indexOf("crevalcore") > -1) { cat = ["Crevalcore", "Blu"]; } if (cleanName.indexOf("ospedale maggiore") > -1) { cat = ["Ospedale Maggiore", "Blu"]; } eta = 6; } else if (cleanName.indexOf("covid monoclonali") > -1) { // Ambulatori monoclonali if (cleanName.indexOf("aosp") > -1) { cat = ["Policlinico S. Orsola", "Blu"]; } if (cleanName.indexOf("ospedale maggiore") > -1) { cat = ["Ospedale Maggiore", "Blu"]; } if (cleanName.indexOf("12-17") > -1) { cat[0] += " (12-17 anni)"; } if (cleanName.indexOf(">=18") > -1) { cat[0] += " (>= 18 anni)"; } eta = 7; } else { // Tamponi Drive if (cleanName.indexOf("drive fiera") > -1) { cat = ["Drive Fiera Bologna", "Drive"]; } if (cleanName.indexOf("drive san lazzaro") > -1) { cat = ["Drive San Lazzaro", "Drive"]; } if (cleanName.indexOf("drive san camillo") > -1) { cat = ["Drive San Lazzaro", "Drive"]; } if (cleanName.indexOf("drive ospedale bentivoglio") > -1) { cat = ["Drive Bentivoglio", "Drive"]; } if (cleanName.indexOf("unipol arena") > -1) { cat = ["Drive Casalecchio", "Drive"]; } if ( cleanName.indexOf("drive pronto soccorso ospedale di bazzano") > -1 ) { cat = ["Drive Bazzano", "Drive"]; } if (cleanName.indexOf("drive pala yuri") > -1) { cat = ["Drive San Lazzaro", "Drive"]; } if (cleanName.indexOf("drive via toscana") > -1) { cat = ["Drive Zola Predosa", "Drive"]; } if (cleanName.indexOf("drive cds ozzano") > -1) { cat = ["Drive Ozzano", "Drive"]; } if (cleanName.indexOf("drive parco nord") > -1) { cat = ["Drive Parco Nord", "Drive"]; } if ( cleanName.indexOf( "drive casa della salute ingresso da via emilia 32" ) > -1 ) { cat = ["Drive San Lazzaro", "Drive"]; } if (cleanName.indexOf("drive istituto ortopedico rizzoli") > -1) { cat = ["Drive Istituto Ortopedico Rizzoli", "Drive"]; } // Ambulatori Tamponi if (cleanName.indexOf("budrio") > -1) { cat = ["Budrio", "Tamponi"]; } if (cleanName.indexOf("san pietro in casale") > -1) { cat = ["San Pietro in Casale", "Tamponi"]; } if (cleanName.indexOf("saragozza") > -1) { cat = ["Poliambulatorio Saragozza", "Tamponi"]; } if (cleanName.indexOf("crevalcore") > -1) { cat = ["Crevalcore", "Tamponi"]; } if (cleanName.indexOf("ospedale maggiore") > -1) { cat = ["Ospedale Maggiore", "Tamponi"]; } if (cleanName.indexOf("piazza rita levi montalcini") > -1) { cat = ["Casa della Salute Casalecchio", "Tamponi"]; } if (cleanName.indexOf("porretta") > -1) { cat = ["Porretta", "Tamponi"]; } if (cleanName.indexOf("orsola") > -1) { cat = ["Policlinico S. Orsola", "Tamponi"]; } if (cleanName.indexOf("boldrini") > -1) { cat = ["Boldrini", "Tamponi"]; } if (cleanName.indexOf("autostazione piazza xx settembre") > -1) { cat = ["Autostazione", "Tamponi"]; } if (cleanName.indexOf("pieve di cento") > -1) { cat = ["Pieve di Cento", "Tamponi"]; } if (cleanName.indexOf("vado tamponi") > -1) { cat = ["Vado", "Tamponi"]; } if (cleanName.indexOf("ospedale bellaria pad tinozzi") > -1) { cat = ["Ospedale Bellaria", "Tamponi"]; } if (cleanName.indexOf("baricella tamponi") > -1) { cat = ["Baricella", "Tamponi"]; } if (cleanName.indexOf("bazzano tamponi") > -1) { cat = ["Bazzano", "Tamponi"]; } if (cleanName.indexOf("casalecchio tamponi") > -1) { cat = ["Casalecchio", "Tamponi"]; } if (cleanName.indexOf("san giovanni in persiceto tamponi") > -1) { cat = ["San Giovanni in Persiceto", "Tamponi"]; } // Specifiche per classi if ( cleanName.indexOf("tutte") > -1 || cleanName.indexOf("aou") > -1 ) { eta = 1; } if (cleanName.indexOf("pediatrici") > -1) { eta = 5; } if (cleanName.indexOf("6-14 anni") > -1) { cat[0] += " (6-14 anni)"; } if ( cleanName.indexOf("maggiore di 6 anni") > -1 || cleanName.indexOf("maggiore 6 anni") > -1 ) { eta = 2; } if ( cleanName.indexOf("maggiore di 14 anni") > -1 || cleanName.indexOf("maggiore 14 anni") > -1 || cleanName.indexOf("adulti drive") > -1 ) { eta = 3; } if ( cleanName.indexOf("screening scuola") > -1 || cleanName.indexOf("personale istituti scolastici") > -1 ) { eta = 4; } if (cleanName.indexOf("maggiore di 4 anni") > -1) { eta = 8; } if (cleanName.indexOf("tamponi antigenici") > -1) { rapido = true; } } if (eta === 0) { console.log(cleanName, [cat, eta]); } return { cat, eta, rapido, }; } function startParsing() { $("#warningText1").html( `Ho trovato ${AGENDE.length} agende. Clicca su Visualizza dettagli per vedere il progresso.
Mano a mano che le agende vengono caricate saranno mostrate in calce alla pagina.` ); const warningHtml = "
"; $(warningHtml).insertAfter(`#warningLoading`); AGENDE.forEach(function (agenda, index) { const numero = agenda.numero; if (!numero) { return console.log(agenda); } setTimeout(function () { getAppuntamenti(agenda, function (error, data) { let color = "#379923"; let status = "ok"; if (error) { if (error === "no_slot_range") { color = "#997a23"; status = "vuota"; } else { color = "#993123"; status = "errore"; } } $(`#status-agenda-${data.agenda.numero}`).html( `[${status}] Agenda ${data.agenda.nome}` ); if (error) { return console.log(error, agenda); } if (data) { const parsedData = parseData(data.descrizioneStruttura); const item = { eta: parsedData.eta, sede: parsedData.cat[0], tipo: parsedData.cat[1], rapido: parsedData.rapido, agenda: data.agenda, dataErogazione: data.dataErogazione, nomeCompleto: data.descrizioneStruttura, primoAppuntamento: data.primoAppuntamento, }; if ($(`#${item.eta}`).length === 0) { const background = item.eta === 7 ? "#4b371e; background-color: #f0dcc7" : "#7AACC5"; const outerHtml = `
${ CODICI_ETA[item.eta] }
`; $(outerHtml).appendTo("#agende-covid"); } if ($(`#${item.eta}-${item.tipo}`).length === 0) { const typeHtml = `

${ TIPI[item.tipo] }

`; $(typeHtml).appendTo(`#${item.eta}`); } if ($(`#agenda-item-${item.agenda.numero}`).length === 0) { const parsedDataErogazione = new Intl.DateTimeFormat( "it" ).format(new Date(item.dataErogazione)); const agendaHtml = `

${ item.sede }: ${parsedDataErogazione} (${ item.primoAppuntamento })${ item.rapido ? "*" : "" }

`; $(agendaHtml).appendTo(`#${item.eta}-${item.tipo}`); } sortList(`#${item.eta}-${item.tipo}`, "p"); sortList("#agende-covid", ".agenda-titolo"); } }); }, index * BATCH_TIME); }); } function addWarning() { const html = `
PRENOTAZIONE SEMPLIFICATA
Per informazioni, aggiornamenti, e se vuoi supportare lo sviluppo di questa funzione visita www.andreacassani.com/apps/agenda-tamponi.

L'applicazione ha caricato le agende con slot entro i prossimi ${PARSE_RANGE_DAYS} giorni.

Le agende contrassegnate con * effettuano tamponi antigenici.

Visualizza dettagli

`; $(html).insertAfter( `#${$(".schede-covid") .eq($(".schede-covid").length - 1) .attr("id")}` ); } function startExtension() { $("#startExtension").attr("disabled", true); if (IS_PARSED) { alert( "Richiesta in corso o già completata, attendi o ricarica la pagina." ); } else { IS_PARSED = true; addWarning(); startParsing(); } } const prenotazioneSemplificataButton = $( '' ); prenotazioneSemplificataButton.click(function () { startExtension(); }); prenotazioneSemplificataButton.insertAfter( $("[name=selezionaAppuntamentoButton]") ); $("select[name=strutturaRicercaAppuntamento] option").each(function ( _, item ) { AGENDE.push({ numero: $(item).val(), nome: $(item).text(), }); }); } function agendaTamponiMenu() { function createDivMenu() { const covidHtml = ` `; $("#top_cvd19").html(covidHtml); } function createTempDivMenu() { const covidHtml = `
 

COVID-19 Menu COVID-19

    Caricamento in corso...

`; $(".box-sx.prf").after(covidHtml); } function createiFrame() { $('') .insertAfter("body") .hide() .on("load", function () { createDivMenu(); }); } createTempDivMenu(); createiFrame(); } if ( window.location.href.match( /^https:\/\/www\.progetto-sole\.it\/riservata.*$/ ) ) { agendaTamponiMenu(); } if ( window.location.href.match( /^https:\/\/ws\.bolognaausl\.progetto-sole\.it\/soleweb\/\?wicket:interface.*$/ ) ) { prenotazioneTamponi(); } })(); })(window.jQuery.noConflict(true));