Aggiunti file javascript
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
// ==UserScript==
|
||||
// @name Automazione DATI COC
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 7.0
|
||||
// @description Polling 2.5s, Nessun refresh dopo upload, Dati persistenti in memoria
|
||||
// @match *://www.ilportaledellautomobilista.it/immatricolazioni/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @grant GM_setValue
|
||||
// @grant GM_getValue
|
||||
// @grant GM_addStyle
|
||||
// @connect localhost
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// --- CONFIGURAZIONE ---
|
||||
const SEARCH_URL = "https://www.ilportaledellautomobilista.it/immatricolazioni/certificatoConformitaDatiTecniciVE/Read_initAction.action?pageStatus=SEARCH";
|
||||
const LOCAL_GET_URL = "https://localhost/hook/dati4.php";
|
||||
const LOCAL_POST_URL = "https://localhost/hook/ans4.php";
|
||||
const POLLING_MS = 2500;
|
||||
|
||||
const clean = (val) => (val === "." || val === undefined || val === null) ? "" : val;
|
||||
|
||||
// --- STILE UI (Allineato a Destra) ---
|
||||
GM_addStyle(`
|
||||
#m-container { position: fixed; right: 3cm; top: 5cm; z-index: 9999; display: flex; flex-direction: column; gap: 10px; }
|
||||
.m-btn { padding: 12px 18px; border: none; border-radius: 5px; color: white; font-weight: bold; cursor: pointer; box-shadow: 2px 2px 5px rgba(0,0,0,0.3); font-family: sans-serif; min-width: 220px; }
|
||||
#btn-compila { background-color: #ffc107; color: #000; }
|
||||
#btn-upload { background-color: #dc3545; cursor: not-allowed; opacity: 0.6; }
|
||||
#btn-upload.active { background-color: #28a745; cursor: pointer; opacity: 1; }
|
||||
#status-info { background: white; padding: 5px; font-size: 10px; border: 1px solid #ccc; text-align: center; border-radius: 3px; }
|
||||
`);
|
||||
|
||||
// --- CREAZIONE MENU ---
|
||||
const container = document.createElement('div');
|
||||
container.id = 'm-container';
|
||||
|
||||
const infoBox = document.createElement('div');
|
||||
infoBox.id = 'status-info';
|
||||
infoBox.innerText = 'In attesa di dati...';
|
||||
|
||||
const btnCompila = document.createElement('button');
|
||||
btnCompila.className = 'm-btn';
|
||||
btnCompila.id = 'btn-compila';
|
||||
btnCompila.innerText = '1. CERCA VEICOLI';
|
||||
|
||||
const btnUpload = document.createElement('button');
|
||||
btnUpload.className = 'm-btn';
|
||||
btnUpload.id = 'btn-upload';
|
||||
btnUpload.innerText = '2. ATTESA TABELLA...';
|
||||
btnUpload.disabled = true;
|
||||
|
||||
container.appendChild(infoBox);
|
||||
container.appendChild(btnCompila);
|
||||
container.appendChild(btnUpload);
|
||||
document.body.appendChild(container);
|
||||
|
||||
// Aggiorna l'etichetta info se ci sono dati salvati
|
||||
const aggiornaInfoUI = () => {
|
||||
const d = GM_getValue("lastTaskData");
|
||||
if(d) infoBox.innerText = "Dati pronti: " + (d.valore1 || "Caricati");
|
||||
};
|
||||
aggiornaInfoUI();
|
||||
|
||||
// --- CONTROLLO TABELLA REAL-TIME ---
|
||||
setInterval(() => {
|
||||
const table = document.getElementById('listTable');
|
||||
const rows = table ? table.querySelectorAll('tbody tr') : [];
|
||||
if (table && rows.length > 0) {
|
||||
btnUpload.classList.add('active');
|
||||
btnUpload.disabled = false;
|
||||
btnUpload.innerText = '2. INVIA DATI (Pronto)';
|
||||
} else {
|
||||
btnUpload.classList.remove('active');
|
||||
btnUpload.disabled = true;
|
||||
btnUpload.innerText = '2. ATTESA TABELLA...';
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// --- FUNZIONE POLLING ---
|
||||
function startPolling() {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: LOCAL_GET_URL,
|
||||
nocache: true,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
if (data.tipo === "DATI-COC" && data.task === "fare") {
|
||||
console.log("Nuovo task ricevuto:", data);
|
||||
|
||||
// Salviamo i dati (sovrascrivendo i precedenti)
|
||||
GM_setValue("lastTaskData", data);
|
||||
aggiornaInfoUI();
|
||||
|
||||
// Comunichiamo al server che il task è stato preso in carico
|
||||
aggiornaStatoTask(data);
|
||||
|
||||
// Esecuzione automatica solo se siamo nella pagina corretta
|
||||
if (window.location.href.includes("pageStatus=SEARCH")) {
|
||||
eseguiAutomazione(data);
|
||||
} else {
|
||||
window.location.href = SEARCH_URL;
|
||||
}
|
||||
}
|
||||
} catch (e) { }
|
||||
setTimeout(startPolling, POLLING_MS);
|
||||
},
|
||||
onerror: () => setTimeout(startPolling, POLLING_MS)
|
||||
});
|
||||
}
|
||||
|
||||
function aggiornaStatoTask(originalData) {
|
||||
let updateData = {...originalData};
|
||||
updateData.task = "COMPLETATO";
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: LOCAL_GET_URL,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: JSON.stringify(updateData)
|
||||
});
|
||||
}
|
||||
|
||||
function eseguiAutomazione(params) {
|
||||
const familyInput = document.querySelector('input[name*="VEFrom.descrizioneFamigliaVeicolo"]');
|
||||
if (familyInput) {
|
||||
const inputs = document.querySelectorAll('input');
|
||||
inputs.forEach(input => {
|
||||
if (input.name.includes("VEFrom.descrizioneFamigliaVeicolo")) input.value = clean(params.valore1);
|
||||
if (input.name.includes("VEFrom.descrizioneVarianteVeicolo")) input.value = clean(params.valore2);
|
||||
if (input.name.includes("VE.codiceOmologazioneEuropea")) input.value = clean(params.valore3);
|
||||
if (input.name.includes("VE.codiceMarchioVeicolo")) input.value = clean(params.valore4);
|
||||
if (input.name.includes("progressivoCostruttoreVeicolo")) input.value = clean(params.valore5);
|
||||
});
|
||||
|
||||
const btnSearch = document.getElementById('RicercaCertificatoConformitaDatiTecniciVE_button_value_searchElement');
|
||||
if (btnSearch) btnSearch.click();
|
||||
}
|
||||
}
|
||||
|
||||
function validaELeggiTabella() {
|
||||
const table = document.getElementById('listTable');
|
||||
if (!table) return;
|
||||
|
||||
const rows = table.querySelectorAll('tbody tr');
|
||||
let records = [];
|
||||
rows.forEach(row => {
|
||||
const cells = Array.from(row.querySelectorAll('td'))
|
||||
.filter(td => !td.querySelector('input[type="radio"]'))
|
||||
.map(td => td.innerText.trim());
|
||||
if (cells.length > 0) records.push(cells);
|
||||
});
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: LOCAL_POST_URL,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: JSON.stringify({ tabella_dati: records }),
|
||||
onload: function(response) {
|
||||
try {
|
||||
const res = JSON.parse(response.responseText);
|
||||
if (res.status === "ok") {
|
||||
// alert("INVIO RIUSCITO: " + res.messaggio);
|
||||
// NOTA: Non cancelliamo GM_setValue né ricarichiamo la pagina qui.
|
||||
} else {
|
||||
alert("ERRORE PHP: " + res.messaggio);
|
||||
}
|
||||
} catch (e) {
|
||||
alert("Dati inviati al server.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
btnCompila.addEventListener('click', () => {
|
||||
const d = GM_getValue("lastTaskData");
|
||||
if(d) {
|
||||
eseguiAutomazione(d);
|
||||
} else {
|
||||
alert("Nessun dato in memoria. Attendi il caricamento automatico dal server.");
|
||||
}
|
||||
});
|
||||
|
||||
btnUpload.addEventListener('click', validaELeggiTabella);
|
||||
|
||||
startPolling();
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,59 @@
|
||||
// ==UserScript==
|
||||
// @name Capture URL Transitions
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.0
|
||||
// @description Salva tutti i cambi di URL e i parametri authcode in una variabile globale
|
||||
// @author Tu
|
||||
// @match https://www.ilportaledeltrasporto.it/*
|
||||
// @run-at document-start
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Variabile globale dove verranno salvati tutti i passaggi
|
||||
window.capturedURLs = [];
|
||||
|
||||
function logURL(method) {
|
||||
const currentURL = window.location.href;
|
||||
const entry = {
|
||||
timestamp: new Date().toLocaleTimeString(),
|
||||
method: method,
|
||||
url: currentURL
|
||||
};
|
||||
|
||||
window.capturedURLs.push(entry);
|
||||
|
||||
// Stampa in console così puoi vederlo in tempo reale
|
||||
console.log(`%chttps://medium.com/data-science/the-capture-recapture-method-dc9985b928da: %c${currentURL}`, "color: orange; font-weight: bold;", "color: cyan;");
|
||||
|
||||
// Se contiene l'authcode, evidenzialo con un alert o un log speciale
|
||||
if (currentURL.includes('authcode')) {
|
||||
console.error("!!! TROVATO AUTHCODE !!!", currentURL);
|
||||
}
|
||||
}
|
||||
|
||||
// Intercettiamo i metodi usati dalle Single Page Application (React)
|
||||
const originalPushState = history.pushState;
|
||||
const originalReplaceState = history.replaceState;
|
||||
|
||||
history.pushState = function() {
|
||||
originalPushState.apply(this, arguments);
|
||||
logURL('pushState');
|
||||
};
|
||||
|
||||
history.replaceState = function() {
|
||||
originalReplaceState.apply(this, arguments);
|
||||
logURL('replaceState');
|
||||
};
|
||||
|
||||
// Intercettiamo i tasti avanti/indietro del browser
|
||||
window.addEventListener('popstate', function() {
|
||||
logURL('popstate');
|
||||
});
|
||||
|
||||
// Registriamo l'URL iniziale
|
||||
logURL('initial-load');
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,54 @@
|
||||
// ==UserScript==
|
||||
// @name Click "Gestisci le istanze"
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 3.0
|
||||
// @description Cerca e preme il pulsante con testo specifico
|
||||
// @author YourName
|
||||
// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa*
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Funzione per cercare e cliccare
|
||||
function findAndClick() {
|
||||
// Recupera tutti i pulsanti nella pagina
|
||||
const buttons = Array.from(document.querySelectorAll('button'));
|
||||
|
||||
// Cerca il pulsante che contiene il testo desiderato (case-sensitive)
|
||||
const targetButton = buttons.find(btn =>
|
||||
btn.textContent.trim().includes("Gestisci le istanze")
|
||||
);
|
||||
|
||||
if (targetButton) {
|
||||
console.log("Pulsante 'Gestisci le istanze' trovato! Clicco...");
|
||||
|
||||
// Focus e click per massima compatibilità
|
||||
targetButton.focus();
|
||||
targetButton.click();
|
||||
|
||||
// Restituisce true se ha trovato il pulsante
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Usiamo un MutationObserver: è più efficiente del timer perché
|
||||
// "osserva" i cambiamenti del sito e interviene appena appare il tasto
|
||||
const observer = new MutationObserver((mutations, obs) => {
|
||||
if (findAndClick()) {
|
||||
obs.disconnect(); // Una volta cliccato, smette di osservare
|
||||
}
|
||||
});
|
||||
|
||||
// Inizia a osservare i cambiamenti nel body della pagina
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Eseguiamo anche un controllo immediato al caricamento
|
||||
window.addEventListener('load', findAndClick);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,118 @@
|
||||
// ==UserScript==
|
||||
// @name Correggi Offset COLLAUDO Portale
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.0
|
||||
// @description Correzione puntuale: elimina sfasamento in testa e recupera coda dal campo successivo
|
||||
// @author Gemini+Gatto.
|
||||
// @match https://www.ilportaledellautomobilista.it/revisioni/certificatoApprovazioneVeicolo/*
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// 0. STATO DI ESECUZIONE (Salvato nella sessione del browser)
|
||||
// Usiamo sessionStorage così se l'utente ricarica la pagina, lo stato si resetta.
|
||||
let giaEseguito = false;
|
||||
|
||||
// --- 1. CONFIGURAZIONE FILTRI ---
|
||||
const targetPhrase = "Dettaglio Certificato Approvazione Veicolo";
|
||||
//const targetDomain = "www.ilportaledeltrasporto.it";
|
||||
|
||||
// --- 2. VERIFICA CONDIZIONI DI ATTIVAZIONE ---
|
||||
|
||||
if (!document.body.innerText.includes(targetPhrase)) {
|
||||
console.log("Script disattivato: Frase specifica non trovata nella pagina.");
|
||||
return;
|
||||
}
|
||||
|
||||
function correggiValorePerValore() {
|
||||
const baseID = "DettaglioCertificatoApprovazioneVeicolo_richiestaCertificatoApprovazioneVeicoloView_righeDescrittiveList_";
|
||||
const numCampi = 12; // Da 0 a 11 (a-l)
|
||||
let v = [];
|
||||
|
||||
if (giaEseguito) {
|
||||
console.warn("Tentativo duplicato: USCITA o ricaricamento pagina in corso...");
|
||||
console.log("Script disattivato: Gia apportate modifiche.");
|
||||
// window.location.reload(); // Forza il refresh (F5)
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Carichiamo i valori attuali in un array v (v[0]=a, v[1]=b, ..., v[11]=l)
|
||||
for (let i = 0; i < numCampi; i++) {
|
||||
let el = document.getElementById(baseID + i + "_");
|
||||
v.push(el ? el.value : "");
|
||||
}
|
||||
|
||||
console.log("Valori letti prima della correzione:", v);
|
||||
|
||||
let v_corr = new Array(numCampi);
|
||||
|
||||
// 2. Applicazione della strategia definita dall'utente
|
||||
// a_corr = a inalterato
|
||||
v_corr[0] = v[0];
|
||||
|
||||
// Da b a k (indici da 1 a 10)
|
||||
// b_corr (i=1): elimina 1 char, aggiunge primi 1 di c (v[2])
|
||||
// c_corr (i=2): elimina 2 char, aggiunge primi 2 di d (v[3])
|
||||
// ...
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
let n_da_eliminare = i;
|
||||
let n_da_recuperare = i;
|
||||
|
||||
// Prendiamo il campo corrente, togliamo l'inizio
|
||||
let parte_restante = v[i].substring(n_da_eliminare);
|
||||
|
||||
// Prendiamo i caratteri "scivolati" dal campo successivo
|
||||
let coda_recuperata = v[i+1].substring(0, n_da_recuperare);
|
||||
|
||||
// Componiamo il valore corretto
|
||||
v_corr[i] = parte_restante + coda_recuperata;
|
||||
|
||||
console.log(`Debug Cella ${i}: rimosse ${n_da_eliminare} in testa, aggiunte ${n_da_recuperare} da cella successiva.`);
|
||||
}
|
||||
|
||||
// l_corr (l'ultimo campo, indice 11) - presumibilmente resta la parte rimanente o inalterato
|
||||
v_corr[11] = v[11].substring(11);
|
||||
|
||||
// 3. Scrittura dei valori corretti nei campi HTML
|
||||
for (let i = 0; i < numCampi; i++) {
|
||||
let el = document.getElementById(baseID + i + "_");
|
||||
if (el) {
|
||||
// Assicuriamoci che non superi mai i 36 caratteri (limite database)
|
||||
el.value = v_corr[i].substring(0, 36);
|
||||
el.style.backgroundColor = "#e8f5e9"; // Feedback visivo (verde)
|
||||
el.style.border = "1px solid #2e7d32";
|
||||
}
|
||||
}
|
||||
|
||||
giaEseguito = true;
|
||||
|
||||
// alert("Correzione applicata secondo lo schema definito.");
|
||||
}
|
||||
|
||||
// Creazione del Pulsante (3cm da destra, 8cm dall'alto)
|
||||
const btn = document.createElement('button');
|
||||
btn.type = "button";
|
||||
btn.innerHTML = "CORREGGI";
|
||||
btn.style.cssText = `
|
||||
position: fixed;
|
||||
right: 3cm;
|
||||
top: 4cm;
|
||||
z-index: 10000;
|
||||
padding: 12px 20px;
|
||||
background-color: #ff5722;
|
||||
color: white;
|
||||
border: 2px solid #e64a19;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.3);
|
||||
`;
|
||||
|
||||
btn.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
correggiValorePerValore();
|
||||
};
|
||||
|
||||
document.body.appendChild(btn);
|
||||
})();
|
||||
@@ -0,0 +1,645 @@
|
||||
// ==UserScript==
|
||||
// @name DOC_NRAP & AB_NRAP portale trasporto v4.5 WORKING.
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 4.5
|
||||
// @description Automazione DOC_NRAP e AB_NRAP con gestione modale di conferma
|
||||
// @author Tu
|
||||
// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @connect localhost
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// --- VARIABILI DI STATO ---
|
||||
let TELAIO = '';
|
||||
let VALORE2 = '0';
|
||||
let VALORE3 = '';
|
||||
let TIPO_ATTUALE = '';
|
||||
let taskAttivo = false;
|
||||
let downloadInCorso = false;
|
||||
let completatoLocalmente = false;
|
||||
const ENDPOINT_GET = 'http://localhost/hook/dati2.php';
|
||||
|
||||
// --- HELPER FUNCTIONS ---
|
||||
|
||||
// Funzione per discriminare lo stato delle schede/tessere
|
||||
|
||||
function getTessereStatus() {
|
||||
let stati = { Tess1: "Sconosciuto", Tess2: "Sconosciuto", Tess3: "Sconosciuto" };
|
||||
|
||||
const cardContainers = document.querySelectorAll('.CardComponent.d-flex.col');
|
||||
|
||||
// Se non ci sono tessere, esci silenziosamente senza fare log di errore
|
||||
if (cardContainers.length === 0) {
|
||||
return null; // Restituiamo null per capire che non siamo nella dashboard
|
||||
}
|
||||
|
||||
cardContainers.forEach((container, index) => {
|
||||
const article = container.querySelector('article.Card');
|
||||
const h2 = container.querySelector('.cardText h2');
|
||||
|
||||
if (article && h2) {
|
||||
const titolo = h2.innerText.trim().toLowerCase();
|
||||
let statoRilevato = "Sconosciuto";
|
||||
|
||||
// Verifica lo stato dalle classi dell'elemento article
|
||||
if (article.classList.contains('Active')) statoRilevato = "Attivo";
|
||||
else if (article.classList.contains('Locked')) statoRilevato = "Bloccato";
|
||||
else if (article.classList.contains('Completed')) statoRilevato = "Completato";
|
||||
|
||||
// Mappatura precisa basata sul testo dell'H2
|
||||
if (titolo.includes("verifica documentazione")) {
|
||||
stati.Tess1 = statoRilevato;
|
||||
} else if (titolo.includes("visita e prova")) {
|
||||
stati.Tess2 = statoRilevato;
|
||||
} else if (titolo.includes("abilitazione telaio")) {
|
||||
stati.Tess3 = statoRilevato;
|
||||
}
|
||||
|
||||
// console.log(`[TM] Rilevata Tessera: "${h2.innerText.trim()}" | Stato: ${statoRilevato}`);
|
||||
}
|
||||
});
|
||||
|
||||
return stati;
|
||||
}
|
||||
|
||||
function getTessereStatus_old() {
|
||||
let stati = {
|
||||
Tess1: "Sconosciuto",
|
||||
Tess2: "Sconosciuto",
|
||||
Tess3: "Sconosciuto"
|
||||
};
|
||||
|
||||
// Seleziona i contenitori basandosi sulla classe che hai indicato
|
||||
const cardContainers = document.querySelectorAll('.CardComponent.d-flex.col');
|
||||
|
||||
if (cardContainers.length === 0) {
|
||||
console.warn("[TM] Nessun contenitore CardComponent trovato.");
|
||||
return stati;
|
||||
}
|
||||
|
||||
cardContainers.forEach((container, index) => {
|
||||
const article = container.querySelector('article.Card');
|
||||
const h2 = container.querySelector('.cardText h2');
|
||||
|
||||
if (article && h2) {
|
||||
const titolo = h2.innerText.trim().toLowerCase();
|
||||
let statoRilevato = "Sconosciuto";
|
||||
|
||||
// Verifica lo stato dalle classi dell'elemento article
|
||||
if (article.classList.contains('Active')) statoRilevato = "Attivo";
|
||||
else if (article.classList.contains('Locked')) statoRilevato = "Bloccato";
|
||||
else if (article.classList.contains('Completed')) statoRilevato = "Completato";
|
||||
|
||||
// Mappatura precisa basata sul testo dell'H2
|
||||
if (titolo.includes("verifica documentazione")) {
|
||||
stati.Tess1 = statoRilevato;
|
||||
} else if (titolo.includes("visita e prova")) {
|
||||
stati.Tess2 = statoRilevato;
|
||||
} else if (titolo.includes("abilitazione telaio")) {
|
||||
stati.Tess3 = statoRilevato;
|
||||
}
|
||||
|
||||
// console.log(`[TM] Rilevata Tessera: "${h2.innerText.trim()}" | Stato: ${statoRilevato}`);
|
||||
}
|
||||
});
|
||||
|
||||
return stati;
|
||||
}
|
||||
|
||||
// Pulizia stringhe: rimuove ogni spazio (inizio, fine, centro) e porta in maiuscolo
|
||||
function cleanString(str) {
|
||||
if (!str) return "";
|
||||
return str.toString().replace(/\s+/g, '').toUpperCase();
|
||||
}
|
||||
|
||||
// Click sicuro per elementi React
|
||||
function clickReactSafe(element) {
|
||||
if (!element || typeof element.dispatchEvent !== 'function') return;
|
||||
const opts = { bubbles: true, cancelable: true, view: window.unsafeWindow || window };
|
||||
try {
|
||||
element.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
element.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
element.click();
|
||||
} catch (e) {
|
||||
element.dispatchEvent(new Event('mousedown', { bubbles: true }));
|
||||
element.dispatchEvent(new Event('mouseup', { bubbles: true }));
|
||||
element.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Premere il pulsante "Procedi" della tessera ennesima (1-based).
|
||||
* @param {number} n - Indice della tessera (1 per la prima, 2 per la seconda, ecc.)
|
||||
*/
|
||||
function Procedi(n) {
|
||||
console.log(`[TM] Test Procedi(${n}) avviato...`);
|
||||
|
||||
// CORREZIONE: Le classi devono essere unite dai punti senza spazi
|
||||
// perché appartengono allo stesso elemento div
|
||||
const cardContainers = document.querySelectorAll('.CardComponent.d-flex.col');
|
||||
|
||||
if (cardContainers.length === 0) {
|
||||
console.error("[TM] ERRORE: Nessun contenitore trovato. Verificare il selettore .CardComponent.d-flex.col");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[TM] Tessere trovate in pagina: ${cardContainers.length}`);
|
||||
|
||||
// Controllo indice
|
||||
if (n < 1 || n > cardContainers.length) {
|
||||
console.error(`[TM] ERRORE: Indice ${n} non valido. Tessere disponibili: ${cardContainers.length}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Selezioniamo la tessera corretta (n-1)
|
||||
const targetCard = cardContainers[n - 1];
|
||||
console.log(`[TM] Opero sulla tessera #${n}:`, targetCard.querySelector('h2')?.innerText);
|
||||
|
||||
// Cerchiamo il pulsante Procedi
|
||||
// Nota: nell'HTML inviato la classe del footer è "cardFooter" (minuscolo/maiuscolo come nel DOM)
|
||||
const btnProcedi = Array.from(targetCard.querySelectorAll('button'))
|
||||
.find(b => b.textContent.trim().toUpperCase() === 'PROCEDI');
|
||||
|
||||
if (!btnProcedi) {
|
||||
console.error(`[TM] Pulsante 'Procedi' non trovato nella tessera #${n}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (btnProcedi.disabled) {
|
||||
console.warn(`[TM] Il pulsante della tessera #${n} è DISABILITATO.`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[TM] Click sulla tessera #${n}...`);
|
||||
clickReactSafe(btnProcedi);
|
||||
};
|
||||
|
||||
// Input sicuro per elementi React
|
||||
|
||||
function setInputReactSafe(element, value) {
|
||||
if (!element) return;
|
||||
|
||||
// Determina se è un input o una textarea per usare il prototipo corretto
|
||||
const prototype = element.tagName === 'TEXTAREA'
|
||||
? HTMLTextAreaElement.prototype
|
||||
: HTMLInputElement.prototype;
|
||||
|
||||
const setter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
|
||||
|
||||
element.focus();
|
||||
setter.call(element, value);
|
||||
|
||||
// Trigger degli eventi per far capire a React che il testo è cambiato
|
||||
element.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
element.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
element.dispatchEvent(new Event('blur', { bubbles: true }));
|
||||
}
|
||||
|
||||
function setInputReactSafe_old(input, value) {
|
||||
if (!input) return;
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
|
||||
input.focus();
|
||||
setter.call(input, value);
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
// Gestione della modale di conferma per AB_NRAP
|
||||
function gestisciModaleConferma() {
|
||||
const modale = document.querySelector('.ModalsPortal__container.mx-auto');
|
||||
if (modale) {
|
||||
const btnConfermaModale = Array.from(modale.querySelectorAll('button'))
|
||||
.find(b => {
|
||||
const spans = b.querySelectorAll('span');
|
||||
return Array.from(spans).some(s => s.textContent.trim() === "Conferma");
|
||||
});
|
||||
|
||||
if (btnConfermaModale) {
|
||||
console.log("[TM] Pulsante 'Conferma' trovato nella modale. Clicco...");
|
||||
clickReactSafe(btnConfermaModale);
|
||||
// Attendiamo che la modale si chiuda e il sistema elabori prima di segnare fine task
|
||||
setTimeout(segnaComeCompletato, 3000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- LOGICA SERVER ---
|
||||
function avviaDownloadDocumenti() {
|
||||
if (downloadInCorso) return;
|
||||
|
||||
const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn'));
|
||||
if (tuttiIBottoni.length === 0) return;
|
||||
|
||||
downloadInCorso = true;
|
||||
const titoliGiaVisti = new Set();
|
||||
let delayDoc = 0;
|
||||
|
||||
tuttiIBottoni.forEach((btn, index, array) => {
|
||||
const riga = btn.closest('tr');
|
||||
const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim();
|
||||
|
||||
if (!titoliGiaVisti.has(titolo)) {
|
||||
titoliGiaVisti.add(titolo);
|
||||
|
||||
setTimeout(() => {
|
||||
console.log(`[TM] 1. Avvio Download: ${titolo}`);
|
||||
clickReactSafe(btn);
|
||||
|
||||
// --- SEQUENZA MODALE ---
|
||||
|
||||
// STEP A: Click Esporta File (dopo 1.2 secondi)
|
||||
setTimeout(() => {
|
||||
const btnEsporta = Array.from(document.querySelectorAll('button.btn-primary.btn-xs'));
|
||||
|
||||
if (btnEsporta) {
|
||||
console.log(`[TM] 2. Click Esporta File per: ${titolo}`);
|
||||
clickReactSafe(btnEsporta);
|
||||
}
|
||||
|
||||
// STEP B: Click Chiudi Modale (dopo altri 1.5 secondi dal click esporta)
|
||||
setTimeout(() => {
|
||||
const btnChiudiModale = document.querySelector('button.ModalContent__header--btn');
|
||||
if (btnChiudiModale) {
|
||||
console.log(`[TM] 3. Chiusura modale per: ${titolo}`);
|
||||
clickReactSafe(btnChiudiModale);
|
||||
}
|
||||
}, 1500);
|
||||
|
||||
}, 1200);
|
||||
// -----------------------
|
||||
|
||||
if (index === array.length - 1) {
|
||||
setTimeout(segnaComeCompletato, 5000);
|
||||
}
|
||||
}, delayDoc);
|
||||
|
||||
delayDoc += 3000;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fetchDati() {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: ENDPOINT_GET,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
const targetHome = 'https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze';
|
||||
|
||||
// Cerca questo blocco dentro fetchDati() e sostituiscilo:
|
||||
|
||||
if (data.tipo === 'RESET_NRAP') {
|
||||
console.log("[TM] Ricevuto comando RESET. Fermo i task e avviso il server...");
|
||||
|
||||
// 1. Impostiamo lo stato su RESET così segnaComeCompletato() sa cosa inviare
|
||||
TIPO_ATTUALE = 'RESET_NRAP';
|
||||
TELAIO = '';
|
||||
VALORE2 = '0';
|
||||
VALORE3 = '';
|
||||
|
||||
// 2. Chiamiamo la funzione che già possiedi per notificare il server
|
||||
segnaComeCompletato();
|
||||
|
||||
// 3. Opzionale: Torna in home solo se non ci sei già
|
||||
if (window.location.href !== targetHome) {
|
||||
window.location.href = targetHome;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((data.tipo === 'DOC_NRAP' || data.tipo === 'AB_NRAP') && data.task === 'fare') {
|
||||
|
||||
if (TELAIO !== '' && TELAIO !== data.valore1) {
|
||||
TELAIO = data.valore1;
|
||||
window.location.href = targetHome;
|
||||
return;
|
||||
}
|
||||
|
||||
if (TELAIO !== data.valore1 || TIPO_ATTUALE !== data.tipo) {
|
||||
TELAIO = data.valore1;
|
||||
VALORE2 = data.valore2;
|
||||
VALORE3 = data.valore3;
|
||||
TIPO_ATTUALE = data.tipo;
|
||||
completatoLocalmente = false;
|
||||
console.log(`[TM] Ricevuto task ${TIPO_ATTUALE} per: ${TELAIO}`);
|
||||
}
|
||||
|
||||
if (!completatoLocalmente) {
|
||||
taskAttivo = true;
|
||||
eseguiAutomazione();
|
||||
}
|
||||
// Dentro l'else di fetchDati (quando data.task NON è 'fare')
|
||||
} else {
|
||||
if (taskAttivo) {
|
||||
console.log("[TM] Nessun task attivo dal server, rilascio il controllo manuale.");
|
||||
}
|
||||
taskAttivo = false;
|
||||
completatoLocalmente = false; // Rimuovi o commenta questa riga se vuoi evitare loop continui
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[TM] Errore parsing dati", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function segnaComeCompletato() {
|
||||
if (completatoLocalmente) return;
|
||||
completatoLocalmente = true;
|
||||
taskAttivo = false;
|
||||
|
||||
const payload = {
|
||||
tipo: TIPO_ATTUALE,
|
||||
task: "COMPLETATO",
|
||||
valore1: TELAIO,
|
||||
valore2: VALORE2,
|
||||
valore3: VALORE3
|
||||
};
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: ENDPOINT_GET,
|
||||
data: JSON.stringify(payload),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
onload: function() {
|
||||
console.log(`[TM] Task ${TIPO_ATTUALE} completato sul server.`);
|
||||
downloadInCorso = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- AUTOMAZIONE PAGINE ---
|
||||
|
||||
function eseguiAutomazione() {
|
||||
// Se il task non è attivo o abbiamo già finito su questa pagina, esci subito
|
||||
if (!taskAttivo || completatoLocalmente) return;
|
||||
|
||||
const url = window.location.href;
|
||||
|
||||
// --- 1. Pagina di Ricerca ---
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
if (input && TELAIO !== '' && cleanString(input.value) !== cleanString(TELAIO)) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800);
|
||||
}
|
||||
if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500);
|
||||
return; // Fine logica ricerca
|
||||
}
|
||||
|
||||
// --- 2. Gestione Dashboard vs Dettaglio ---
|
||||
// Recuperiamo lo stato delle tessere. getTessereStatus() ora deve restituire null
|
||||
// se non trova i contenitori (come spiegato prima), evitando log di errore.
|
||||
const situazione = getTessereStatus();
|
||||
|
||||
// CASO A: Siamo nella Dashboard (Tessere visibili)
|
||||
if (situazione !== null && !url.includes('dettaglio-istanza') && !url.includes('abilitazione-telaio')) {
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi');
|
||||
|
||||
if (btnProcedi && !btnProcedi.disabled) {
|
||||
if (TIPO_ATTUALE === 'DOC_NRAP' && situazione.Tess1 === "Attivo") {
|
||||
console.log("[TM] Dashboard: Apro Tessera 1 (Documentazione)");
|
||||
setTimeout(() => { Procedi(1); }, 1000);
|
||||
} else if (TIPO_ATTUALE === 'AB_NRAP' && situazione.Tess3 === "Attivo") {
|
||||
console.log("[TM] Dashboard: Apro Tessera 3 (Abilitazione)");
|
||||
setTimeout(() => { Procedi(3); }, 1000);
|
||||
}
|
||||
}
|
||||
return; // Esci: abbiamo gestito la dashboard
|
||||
}
|
||||
|
||||
// CASO B: Siamo nella Pagina di Dettaglio/Compilazione (Abilitazione o Download)
|
||||
if (url.includes('dettaglio-istanza') || url.includes('abilitazione-telaio')) {
|
||||
|
||||
// Sotto-caso: Compilazione Dati (AB_NRAP)
|
||||
if (TIPO_ATTUALE === 'AB_NRAP') {
|
||||
const inputCodImmat = document.getElementById('Codice immatricolazione');
|
||||
const inputNota = document.getElementById('Nota*') || document.getElementById('Nota');
|
||||
|
||||
if (inputCodImmat && inputNota) {
|
||||
console.log("[TM] Pagina compilazione rilevata. Inserisco dati...");
|
||||
|
||||
// Inserimento dati con logica React
|
||||
setInputReactSafe(inputCodImmat, VALORE2);
|
||||
setInputReactSafe(inputNota, VALORE3);
|
||||
|
||||
// Forza il focus out per "fissare" il valore in React
|
||||
inputCodImmat.dispatchEvent(new Event('blur', { bubbles: true }));
|
||||
inputNota.dispatchEvent(new Event('blur', { bubbles: true }));
|
||||
|
||||
console.log("[TM] Compilazione eseguita. Ora l'Observer si ferma.");
|
||||
|
||||
// BLOCCA L'OBSERVER: impostando a true, questa intera funzione
|
||||
// si fermerà al primo IF nei cicli successivi.
|
||||
completatoLocalmente = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Sotto-caso: Download Documenti (DOC_NRAP)
|
||||
else if (TIPO_ATTUALE === 'DOC_NRAP') {
|
||||
if (downloadInCorso) return;
|
||||
|
||||
if (parseInt(VALORE2) > 0) {
|
||||
console.log("[TM] Pagina documenti rilevata. Avvio download...");
|
||||
avviaDownloadDocumenti();
|
||||
} else {
|
||||
console.log("[TM] Nessun documento richiesto (Valore2=0). Chiudo.");
|
||||
segnaComeCompletato();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eseguiAutomazione_old() {
|
||||
if (!taskAttivo || completatoLocalmente) return;
|
||||
|
||||
const url = window.location.href;
|
||||
|
||||
// 1. Pagina di Ricerca
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
if (input && TELAIO !== '' && cleanString(input.value) !== cleanString(TELAIO)) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800);
|
||||
}
|
||||
if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500);
|
||||
//if (btnTabella) console.log("Pulsante Tabella trovato! esegui il comando a mano");
|
||||
}
|
||||
|
||||
// --- 2. Pagina Dashboard (Tessere) ---
|
||||
if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) {
|
||||
const situazione = getTessereStatus();
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi');
|
||||
|
||||
if (btnProcedi && !btnProcedi.disabled) {
|
||||
if (TIPO_ATTUALE === 'DOC_NRAP' && situazione.Tess1 === "Attivo") {
|
||||
setTimeout(() => { Procedi(1); }, 1000);
|
||||
} else if (TIPO_ATTUALE === 'AB_NRAP' && situazione.Tess3 === "Attivo") {
|
||||
setTimeout(() => { Procedi(3); }, 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3. Pagina di Abilitazione (Dettaglio) ---
|
||||
if (url.includes('/abilitazione/') && url.includes('/abilitazione-telaio')) {
|
||||
|
||||
if (TIPO_ATTUALE === 'AB_NRAP') {
|
||||
const inputCodImmat = document.getElementById('Codice immatricolazione');
|
||||
// Cerca la nota sia con che senza asterisco
|
||||
const inputNota = document.getElementById('Nota*') || document.getElementById('Nota');
|
||||
console.log("[TM] Pagina di abilitazione rilevata. Compilo...");
|
||||
if (inputCodImmat && inputNota) {
|
||||
console.log("[TM] Pagina di abilitazione rilevata. Compilo...");
|
||||
|
||||
//setInputReactSafe(inputCodImmat, VALORE2);
|
||||
//setInputReactSafe(inputNota, VALORE3);
|
||||
|
||||
console.log("[TM] Dati inseriti. Ora mi fermo e ti lascio il controllo.");
|
||||
|
||||
// IMPORTANTE: Segniamo come completato localmente solo la "scrittura"
|
||||
// così l'Observer smette di chiamare eseguiAutomazione() per questa pagina.
|
||||
completatoLocalmente = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (TIPO_ATTUALE === 'DOC_NRAP') {
|
||||
if (downloadInCorso) return;
|
||||
if (parseInt(VALORE2) > 0) {
|
||||
avviaDownloadDocumenti();
|
||||
} else {
|
||||
segnaComeCompletato();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function eseguiAutomazione2() {
|
||||
if (!taskAttivo || completatoLocalmente) return;
|
||||
const situazione = getTessereStatus();
|
||||
|
||||
// GUARDIA: Se tutte le tessere sono "Bloccato" o "Sconosciuto",
|
||||
// probabilmente React sta ancora caricando. Fermati e aspetta il prossimo ciclo.
|
||||
if (situazione.Tess1 === "Bloccato" && situazione.Tess2 === "Bloccato") {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = window.location.href;
|
||||
|
||||
// 1. Pagina di Ricerca
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
if (input && TELAIO !== '' && cleanString(input.value) !== cleanString(TELAIO)) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800);
|
||||
}
|
||||
if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500);
|
||||
//if (btnTabella) console.log("Pulsante Tabella trovato! esegui il comando a mano");
|
||||
}
|
||||
|
||||
// 2. Pagina Intermedia (Abilitazione / Dashboard)
|
||||
if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) {
|
||||
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi');
|
||||
|
||||
if (btnProcedi && !btnProcedi.disabled) {
|
||||
|
||||
// --- LOGICA SELETTIVA ---
|
||||
|
||||
if (TIPO_ATTUALE === 'DOC_NRAP') {
|
||||
console.log("Stato tessere al click:", situazione);
|
||||
if (situazione.Tess1 === "Attivo" && situazione.Tess3 === "Bloccato") {
|
||||
console.log("[TM] DOC_NRAP: Tessera 1 pronta. Procedo apertura documenti...");
|
||||
setTimeout(() => { Procedi(1); }, 1000);
|
||||
} else if (situazione.Tess1 === "Completato"){
|
||||
console.warn("[TM] DOC_NRAP: Vista documentazione");
|
||||
} else if (situazione.Tess1 === "Bloccato"){
|
||||
console.warn("[TM] DOC_NRAP: Documentazione bloccata, attendere");
|
||||
}
|
||||
}
|
||||
|
||||
else if (TIPO_ATTUALE === 'AB_NRAP') {
|
||||
// Logica specifica per AB_NRAP (es. solo se Tess3 è Attiva)
|
||||
if (situazione.Tess3 === "Attivo") {
|
||||
console.log("[TM] DOC_NRAP: Tessera 3 Ok si procede a validazione...");
|
||||
setTimeout(() => { Procedi(3); }, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Pagina Dettaglio Istanza
|
||||
if (url.includes('dettaglio-istanza')) {
|
||||
const situazioneInDettaglio = getTessereStatus();
|
||||
|
||||
// CASO A: Operazione AB_NRAP (Solo inserimento dati, NO clic automatico)
|
||||
if (TIPO_ATTUALE === 'AB_NRAP') {
|
||||
const inputCodImmat = document.getElementById('Codice immatricolazione');
|
||||
const inputNota = document.getElementById('Nota*');
|
||||
|
||||
let datiInseriti = false;
|
||||
|
||||
// 1. Inserimento Codice Immatricolazione (Valore2)
|
||||
if (inputCodImmat.value !== VALORE2) {
|
||||
console.log("[TM] Inserisco Codice Immatricolazione:", VALORE2);
|
||||
setInputReactSafe(inputCodImmat, VALORE2);
|
||||
datiInseriti = true;
|
||||
}
|
||||
|
||||
// 2. Inserimento Nota (Valore3)
|
||||
if (inputNota.value !== VALORE3) {
|
||||
console.log("[TM] Inserisco Nota:", VALORE3);
|
||||
setInputReactSafe(inputNota, VALORE3);
|
||||
datiInseriti = true;
|
||||
}
|
||||
|
||||
// 3. Feedback visivo e stop
|
||||
if (datiInseriti) {
|
||||
console.log("[TM] Campi compilati. Attendo interazione manuale per il tasto Conferma.");
|
||||
// Non facciamo nulla: il ciclo MutationObserver continuerà a girare
|
||||
// ma non troverà discrepanze nei valori e non farà clic.
|
||||
}
|
||||
}
|
||||
|
||||
// CASO B: Operazione DOC_NRAP (Download)
|
||||
else if (TIPO_ATTUALE === 'DOC_NRAP') {
|
||||
if (downloadInCorso) return; // Se sto già scaricando, NON rientrare nella funzione
|
||||
if (parseInt(VALORE2) > 0) {
|
||||
avviaDownloadDocumenti();
|
||||
//console.log("Avvio download documenti. Stato attuale tessere:", situazione);
|
||||
} else {
|
||||
console.log("[TM] Valore2 <= 1, chiusura task senza download.");
|
||||
segnaComeCompletato();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// --- INITIALIZATION ---
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
if (taskAttivo) eseguiAutomazione();
|
||||
});
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
setInterval(fetchDati, 2500);
|
||||
fetchDati();
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,118 @@
|
||||
// ==UserScript==
|
||||
// @name EUCARIS php Bridge - VERSIONE ANTI-LOOP
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 7.1
|
||||
// @description Navigazione forzata con blocco dei ricarichi infiniti
|
||||
// @author GATTO + Gemini
|
||||
// @match *://www.ilportaledellautomobilista.it/Info/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @grant GM_setValue
|
||||
// @grant GM_getValue
|
||||
// @connect 192.168.1.33
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const PHP_URL = "http://192.168.1.33/hook/dati1.php";
|
||||
const URL_STEP_1 = "/Info/info/CreateGraph_home.action?SESSION_INFO_NODO_CORRENTE=N370&CRITERIO=99&METODO=/criteria-page/home.jsp";
|
||||
const URL_STEP_2 = "/Info/info/CreateGraph_getFunzioneSelezionata.action?SESSION_INFO_NODO_CORRENTE=N371";
|
||||
const URL_HOME = "/Info/info/CreateGraph_home.action?SESSION_INFO_NODO_CORRENTE=N21&CRITERIO=99&METODO=/criteria-page/home.js";
|
||||
|
||||
let isRedirecting = false;
|
||||
|
||||
// --- FUNZIONE DI SALTO SICURA (EVITA LOOP) ---
|
||||
function safeRedirect(targetPath) {
|
||||
const fullTarget = window.location.origin + targetPath;
|
||||
if (window.location.href !== fullTarget) {
|
||||
console.log("Reindirizzamento a: " + targetPath);
|
||||
isRedirecting = true;
|
||||
window.location.href = fullTarget;
|
||||
} else {
|
||||
console.log("Già a destinazione, evito il loop.");
|
||||
}
|
||||
}
|
||||
|
||||
function autofillEucaris() {
|
||||
const telaioDaInserire = GM_getValue("ultimo_telaio", null);
|
||||
|
||||
if (window.location.href.includes("N371") && telaioDaInserire) {
|
||||
const radio = document.getElementById("CreateGraph_getFunzioneSelezionata_criterio77");
|
||||
const inputTelaio = document.getElementById("CreateGraph_getFunzioneSelezionata_criteri_77__telaio");
|
||||
const inputStato = document.getElementById("CreateGraph_getFunzioneSelezionata_criteri_77__idStato");
|
||||
const btnConfirm = document.getElementById("CreateGraph_getFunzioneSelezionata_button_value_confirm");
|
||||
|
||||
if (radio) radio.checked = true;
|
||||
if (inputTelaio) inputTelaio.value = telaioDaInserire;
|
||||
if (inputStato) inputStato.value = "MCI";
|
||||
|
||||
if (inputTelaio && inputTelaio.value !== "") {
|
||||
GM_setValue("ultimo_telaio", null);
|
||||
if (btnConfirm) {
|
||||
setTimeout(() => { btnConfirm.click(); }, 800);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkTask() {
|
||||
if (isRedirecting) return;
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: PHP_URL + "?nocache=" + new Date().getTime(),
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
if (data.task && data.task.toLowerCase() === "fare") {
|
||||
if (data.valore1 && data.tipo.toUpperCase() === "EUCARIS") {
|
||||
GM_setValue("ultimo_telaio", data.valore1);
|
||||
}
|
||||
eseguiSalto(data);
|
||||
}
|
||||
} catch (e) { }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eseguiSalto(data) {
|
||||
const tipo = data.tipo.toUpperCase();
|
||||
const currentUrl = window.location.href;
|
||||
|
||||
if (tipo === "EUCARIS") {
|
||||
// Se non sono ancora in N370 o N371, vai a Step 1
|
||||
if (!currentUrl.includes("N370") && !currentUrl.includes("N371")) {
|
||||
safeRedirect(URL_STEP_1);
|
||||
}
|
||||
// Se sono in N370, segnalo completato e vado a Step 2
|
||||
else if (currentUrl.includes("N370")) {
|
||||
isRedirecting = true;
|
||||
const update = { ...data, task: "completato" };
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: PHP_URL,
|
||||
data: JSON.stringify(update),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
onload: () => { safeRedirect(URL_STEP_2); }
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (tipo === "RESET") {
|
||||
if (!currentUrl.includes("N21")) { // Salta a home solo se non ci sei già
|
||||
isRedirecting = true;
|
||||
const update = { ...data, task: "completato" };
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: PHP_URL,
|
||||
data: JSON.stringify(update),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
onload: () => { safeRedirect(URL_HOME); }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autofillEucaris();
|
||||
setInterval(checkTask, 3000); // Leggermente più lento per dare tempo alla pagina di stabilizzarsi
|
||||
})();
|
||||
@@ -0,0 +1,92 @@
|
||||
// ==UserScript==
|
||||
// @name Estrattore Manuale Tabella Portale Trasporto
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 2.0
|
||||
// @description Aggiornamento dati tramite tasto Cerca senza ricaricare la pagina
|
||||
// @author Gemini
|
||||
// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @connect 192.168.1.33
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const CONFIG = {
|
||||
endpoint: 'http://192.168.1.33/hook/ans2.php',
|
||||
interval: 6000 // 6 secondi tra un invio e l'altro
|
||||
};
|
||||
|
||||
console.log("%c Script in modalità Manuale Attivo. Imposta i filtri e lo script farà il resto.", "color: #00DBFF; font-weight: bold;");
|
||||
|
||||
function eseguiCiclo() {
|
||||
// 1. Cerca il pulsante "Cerca"
|
||||
const buttons = Array.from(document.querySelectorAll('button'));
|
||||
const searchButton = buttons.find(btn =>
|
||||
btn.innerText.trim().toUpperCase() === "CERCA"
|
||||
);
|
||||
|
||||
if (searchButton) {
|
||||
console.log("Aggiornamento dati (clic su Cerca)...");
|
||||
searchButton.click();
|
||||
|
||||
// 2. Aspetta che la tabella si aggiorni (4 secondi)
|
||||
setTimeout(() => {
|
||||
estraiEInvia();
|
||||
}, 4000);
|
||||
} else {
|
||||
console.warn("Pulsante 'Cerca' non trovato. Riprovo tra 20 secondi.");
|
||||
setTimeout(eseguiCiclo, CONFIG.interval);
|
||||
}
|
||||
}
|
||||
|
||||
function estraiEInvia() {
|
||||
const rows = document.querySelectorAll('[role="row"]');
|
||||
const results = [];
|
||||
|
||||
rows.forEach(row => {
|
||||
const cells = row.querySelectorAll('[role="cell"]');
|
||||
if (cells.length >= 5) {
|
||||
const idIstanza = cells[0].innerText.trim();
|
||||
if (idIstanza !== "" && idIstanza.toLowerCase() !== "identificativo istanza") {
|
||||
results.push({
|
||||
identificativo: idIstanza,
|
||||
data_inserimento: cells[1]?.innerText.trim(),
|
||||
stato: cells[2]?.innerText.trim(),
|
||||
tipologia: cells[3]?.innerText.trim(),
|
||||
targa_telaio: cells[4]?.innerText.trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
console.log(`Invio di ${results.length} record in corso...`);
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: CONFIG.endpoint,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: JSON.stringify(results),
|
||||
onload: function(response) {
|
||||
console.log("%c OK: Dati inviati con successo.", "color: #00FF00;");
|
||||
// 3. Programma il prossimo ciclo senza ricaricare la pagina
|
||||
setTimeout(eseguiCiclo, CONFIG.interval);
|
||||
},
|
||||
onerror: function(err) {
|
||||
console.error("Errore invio server locale. Riprovo tra 20 secondi.");
|
||||
setTimeout(eseguiCiclo, CONFIG.interval);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn("Nessun dato trovato in tabella. Riprovo nel prossimo ciclo.");
|
||||
setTimeout(eseguiCiclo, CONFIG.interval);
|
||||
}
|
||||
}
|
||||
|
||||
// Avvio del primo ciclo dopo 5 secondi dal caricamento della pagina
|
||||
// per darti il tempo di impostare i filtri se vuoi,
|
||||
// altrimenti lo script girerà con i filtri che trova.
|
||||
setTimeout(eseguiCiclo, 5000);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,120 @@
|
||||
// ==UserScript==
|
||||
// @name Estrattore Tabella Portale Trasporto - Fixed
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 3.2
|
||||
// @description Risolto loop infinito su tabella vuota
|
||||
// @author Gemini
|
||||
// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @connect 192.168.1.33
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const CONFIG = {
|
||||
commandEndpoint: 'http://192.168.1.33/hook/dati3.php',
|
||||
answerEndpoint: 'http://192.168.1.33/hook/ans3.php',
|
||||
pollingInterval: 1000,
|
||||
searchDelay: 1500
|
||||
};
|
||||
|
||||
function checkCommand() {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: CONFIG.commandEndpoint,
|
||||
headers: { "Cache-Control": "no-cache" },
|
||||
onload: function(response) {
|
||||
try {
|
||||
const res = JSON.parse(response.responseText);
|
||||
if (res.tipo === "DATI_NRAP" && res.task === "fare") {
|
||||
console.log("%c [COMANDO] Ricevuto 'fare'.", "color: #FFA500; font-weight: bold;");
|
||||
eseguiCiclo();
|
||||
} else {
|
||||
setTimeout(checkCommand, CONFIG.pollingInterval);
|
||||
}
|
||||
} catch (e) {
|
||||
setTimeout(checkCommand, CONFIG.pollingInterval);
|
||||
}
|
||||
},
|
||||
onerror: () => setTimeout(checkCommand, CONFIG.pollingInterval)
|
||||
});
|
||||
}
|
||||
|
||||
function eseguiCiclo() {
|
||||
const buttons = Array.from(document.querySelectorAll('button'));
|
||||
const searchButton = buttons.find(btn => btn.innerText.trim().toUpperCase() === "CERCA");
|
||||
|
||||
if (searchButton) {
|
||||
console.log("[ACTION] Click Cerca...");
|
||||
searchButton.click();
|
||||
setTimeout(estraiEInvia, CONFIG.searchDelay);
|
||||
} else {
|
||||
console.error("[ERRORE] Tasto Cerca non trovato.");
|
||||
// Resettiamo comunque per evitare loop se il tasto sparisce
|
||||
impostaStatoFinale("ERRORE_BOTTONE");
|
||||
}
|
||||
}
|
||||
|
||||
function estraiEInvia() {
|
||||
const rows = document.querySelectorAll('[role="row"]');
|
||||
const results = [];
|
||||
|
||||
rows.forEach(row => {
|
||||
const cells = row.querySelectorAll('[role="cell"]');
|
||||
if (cells.length >= 5) {
|
||||
const idIstanza = cells[0].innerText.trim();
|
||||
if (idIstanza !== "" && idIstanza.toLowerCase() !== "identificativo istanza") {
|
||||
results.push({
|
||||
identificativo: idIstanza,
|
||||
data_inserimento: cells[1]?.innerText.trim(),
|
||||
stato: cells[2]?.innerText.trim(),
|
||||
tipologia: cells[3]?.innerText.trim(),
|
||||
targa_telaio: cells[4]?.innerText.trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (results.length > 0) {
|
||||
console.log(`[DATA] Invio ${results.length} record...`);
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: CONFIG.answerEndpoint,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: JSON.stringify(results),
|
||||
onload: () => {
|
||||
console.log("%c [SUCCESS] Dati inviati.", "color: #00FF00;");
|
||||
impostaStatoFinale("COMPLETATO");
|
||||
},
|
||||
onerror: () => setTimeout(checkCommand, CONFIG.pollingInterval)
|
||||
});
|
||||
} else {
|
||||
// MODIFICA CRUCIALE: Se la tabella è vuota, impostiamo comunque COMPLETATO
|
||||
// per fermare il loop, indicando che non ci sono record.
|
||||
console.warn("[WARN] Tabella vuota. Fermo il comando.");
|
||||
impostaStatoFinale("COMPLETATO_VUOTO");
|
||||
}
|
||||
}
|
||||
|
||||
function impostaStatoFinale(nuovoStato) {
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: CONFIG.commandEndpoint,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: JSON.stringify({
|
||||
tipo: "DATI_NRAP",
|
||||
task: nuovoStato, // Sarà COMPLETATO, COMPLETATO_VUOTO o ERRORE
|
||||
valore1: "0",
|
||||
valore2: "0",
|
||||
valore3: "0"
|
||||
}),
|
||||
onload: function() {
|
||||
console.log(`%c [STATUS] Comando chiuso con stato: ${nuovoStato}`, "color: #FFF; background: #333;");
|
||||
setTimeout(checkCommand, CONFIG.pollingInterval);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
checkCommand();
|
||||
})();
|
||||
@@ -0,0 +1,183 @@
|
||||
// ==UserScript==
|
||||
// @name OTP NTFY Console (Token)
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 2.2
|
||||
// @description Pannello OTP sicuro con Bearer Token e monitoraggio live
|
||||
// @author Gemini + Gatto
|
||||
// @match *://www.ilportaledellautomobilista.it/*
|
||||
// @grant GM_notification
|
||||
// @grant GM_setClipboard
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// --- CONFIGURAZIONE SICURA ---
|
||||
const BASE_URL = "ntfy.dati-web.it";
|
||||
// <--- INCOLLA QUI IL TUO TOKEN tk_...
|
||||
const NTFY_TOKEN = "tk_mh1ox5scgkorten10a7baelpehh6p";
|
||||
|
||||
let currentTopic = localStorage.getItem('otp_topic');
|
||||
let mode = localStorage.getItem('otp_mode');
|
||||
const OTP_REGEX = /(?:^|\s)(\S{8})(?=\s|$)/;
|
||||
|
||||
function injectInterface() {
|
||||
const logo = document.getElementById('logo-portale');
|
||||
if (!logo) {
|
||||
setTimeout(injectInterface, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentLink = logo.closest('a');
|
||||
const anchorPoint = parentLink ? parentLink : logo;
|
||||
|
||||
if (document.getElementById('otp-embedded-panel')) return;
|
||||
|
||||
const navPanel = document.createElement('div');
|
||||
navPanel.id = "otp-embedded-panel";
|
||||
|
||||
// Stile del pannello
|
||||
navPanel.style = `
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-left: 330px;
|
||||
margin-top: 16px;
|
||||
padding: 0 10px;
|
||||
background: #ffffff;
|
||||
border: 1px dashed #0056b3;
|
||||
border-radius: 6px;
|
||||
vertical-align: middle;
|
||||
height: 60px;
|
||||
font-family: Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
pointer-events:auto;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
min-width: 340px !important;
|
||||
max-width: 420px !important;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1) !important;
|
||||
line-height: normal;
|
||||
color: #333 !important;
|
||||
` ;
|
||||
navPanel.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; gap: 4px;">
|
||||
<input type="text" id="topicInput" value="${currentTopic}" placeholder="Topic" style="margin-left: 2px; width: 100px; height: 20px; font-size: 10px; border: 1px solid #ccc; border-radius: 3px; padding: 1px 1px;">
|
||||
<button id="saveConfig" style="margin-left: 2px; width: 102px; height: 22px; font-size: 10px; background: #0056b3; color: white; border: 1px solid; border-radius: 3px; cursor: pointer; font-weight: bold;">AGG. TOPIC</button>
|
||||
</div>
|
||||
|
||||
<div style="margin-left: 15px; border-left: 1px solid #ccc; height: 40px;"></div>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 2px; font-size: 10px; color: #333;">
|
||||
<label style="width: 70px; cursor:pointer; display: flex; align-items: left; gap: 2px;">
|
||||
<input type="radio" name="otpMode" value="notify" ${mode==='notify'?'checked':''}> Notifica
|
||||
</label>
|
||||
<label style="width: 70px; cursor:pointer; display: flex; align-items: left; gap: 2px;">
|
||||
<input type="radio" name="otpMode" value="type" ${mode==='type'?'checked':''}> Digitaz.
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="margin-left: 15px; margin-right: 8px; border-left: 1px solid #ccc; height: 40px;"></div>
|
||||
|
||||
<div style="text-align: center; flex-grow: 1;">
|
||||
<div id="lastCodeLabel" style="font-size: 18px; font-weight: bold; color: #d9534f; letter-spacing: 1px;">---</div>
|
||||
<div id="statusLabel" style="font-size: 9px; color: #28a745; font-weight: bold;">STABILE</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling);
|
||||
|
||||
// Salvataggio impostazioni
|
||||
document.getElementById('saveConfig').addEventListener('click', () => {
|
||||
localStorage.setItem('otp_topic', document.getElementById('topicInput').value.trim());
|
||||
localStorage.setItem('otp_mode', document.querySelector('input[name="otpMode"]:checked').value);
|
||||
location.reload();
|
||||
});
|
||||
|
||||
startListening();
|
||||
}
|
||||
|
||||
async function startListening() {
|
||||
const statusLabel = document.getElementById('statusLabel');
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://${BASE_URL}/${currentTopic}/json`, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${NTFY_TOKEN}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
statusLabel.innerText = "ERRORE TOKEN";
|
||||
statusLabel.style.color = "red";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) throw new Error("Errore connessione");
|
||||
|
||||
statusLabel.innerText = "ONLINE";
|
||||
statusLabel.style.color = "#28a745";
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
const chunk = decoder.decode(value);
|
||||
const lines = chunk.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.trim()) continue;
|
||||
try {
|
||||
const data = JSON.parse(line);
|
||||
if (data.event === 'message' && data.message) {
|
||||
const match = data.message.match(OTP_REGEX);
|
||||
if (match) handleOTP(match[1]);
|
||||
}
|
||||
} catch (e) { console.error("Errore parsing JSON", e); }
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
statusLabel.innerText = "RE-CONNECTING...";
|
||||
statusLabel.style.color = "orange";
|
||||
setTimeout(startListening, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function handleOTP(newOtp) {
|
||||
document.getElementById('lastCodeLabel').innerText = newOtp;
|
||||
GM_setClipboard(newOtp);
|
||||
|
||||
// Notifica di sistema
|
||||
GM_notification({
|
||||
title: "OTP Infocert",
|
||||
text: `Codice: ${newOtp} (Copiato)`,
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
// Se la modalità è "Digita", inserisce l'OTP nel campo attualmente selezionato (focus)
|
||||
if (document.querySelector('input[name="otpMode"]:checked').value === 'type') {
|
||||
const activeInput = document.activeElement;
|
||||
|
||||
// Verifichiamo che l'elemento attivo sia effettivamente un campo di testo
|
||||
if (activeInput && (activeInput.tagName === 'INPUT' || activeInput.tagName === 'TEXTAREA')) {
|
||||
activeInput.value = newOtp;
|
||||
|
||||
// Simula l'evento di input per attivare eventuali validazioni/script della pagina
|
||||
activeInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
activeInput.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
} else {
|
||||
console.warn("Nessun campo di testo selezionato al momento dell'inserimento.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "complete" || document.readyState === "interactive") {
|
||||
injectInterface();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", injectInterface);
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,169 @@
|
||||
// ==UserScript==
|
||||
// @name OTP NTFY Console (Token)
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 2.1
|
||||
// @description Pannello OTP sicuro con Bearer Token e monitoraggio live
|
||||
// @author Gemini + Gatto
|
||||
// @match *://www.ilportaledellautomobilista.it/*
|
||||
// @grant GM_notification
|
||||
// @grant GM_setClipboard
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// --- CONFIGURAZIONE SICURA ---
|
||||
const BASE_URL = "ntfy.dati-web.it";
|
||||
// <--- INCOLLA QUI IL TUO TOKEN tk_...
|
||||
const NTFY_TOKEN = "tk_mh1ox5scgkorten10a7baelpehh6p";
|
||||
|
||||
let currentTopic = localStorage.getItem('otp_topic') || "OTP-Gatto";
|
||||
let mode = localStorage.getItem('otp_gatto_mode') || "notify";
|
||||
const OTP_REGEX = /(?:^|\s)(\S{8})(?=\s|$)/;
|
||||
|
||||
function injectInterface() {
|
||||
const logo = document.getElementById('logo-portale');
|
||||
if (!logo) {
|
||||
setTimeout(injectInterface, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentLink = logo.closest('a');
|
||||
const anchorPoint = parentLink ? parentLink : logo;
|
||||
|
||||
if (document.getElementById('otp-embedded-panel')) return;
|
||||
|
||||
const navPanel = document.createElement('div');
|
||||
navPanel.id = "otp-embedded-panel";
|
||||
|
||||
// Stile del pannello
|
||||
navPanel.style = `
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-left: 300px;
|
||||
margin-top: 16px;
|
||||
padding: 0 15px;
|
||||
background: #f8f9fa;
|
||||
border: 2px solid #0056b3;
|
||||
border-radius: 8px;
|
||||
height: 60px;
|
||||
min-width: 320px;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
z-index: 9999;
|
||||
`;
|
||||
|
||||
navPanel.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; gap: 4px;">
|
||||
<input type="text" id="topicInput" value="${currentTopic}" placeholder="Topic" style="width: 100px; height: 20px; font-size: 11px; border: 1px solid #ccc; border-radius: 3px; padding: 2px 5px;">
|
||||
<button id="saveConfig" style="width: 110px; height: 22px; font-size: 10px; background: #0056b3; color: white; border: none; border-radius: 3px; cursor: pointer; font-weight: bold;">AGG. TOPIC</button>
|
||||
</div>
|
||||
|
||||
<div style="border-left: 1px solid #ccc; height: 40px;"></div>
|
||||
|
||||
<div style="display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: #333;">
|
||||
<label style="cursor:pointer; display: flex; align-items: center; gap: 5px;">
|
||||
<input type="radio" name="otpMode" value="notify" ${mode==='notify'?'checked':''}> Notifica
|
||||
</label>
|
||||
<label style="cursor:pointer; display: flex; align-items: center; gap: 5px;">
|
||||
<input type="radio" name="otpMode" value="type" ${mode==='type'?'checked':''}> Digita
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style="border-left: 1px solid #ccc; height: 40px;"></div>
|
||||
|
||||
<div style="text-align: center; flex-grow: 1;">
|
||||
<div id="lastCodeLabel" style="font-size: 18px; font-weight: bold; color: #d9534f; letter-spacing: 1px;">---</div>
|
||||
<div id="statusLabel" style="font-size: 9px; color: #28a745; font-weight: bold;">STABILE</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling);
|
||||
|
||||
// Salvataggio impostazioni
|
||||
document.getElementById('saveConfig').addEventListener('click', () => {
|
||||
localStorage.setItem('otp_topic', document.getElementById('topicInput').value.trim());
|
||||
localStorage.setItem('otp_gatto_mode', document.querySelector('input[name="otpMode"]:checked').value);
|
||||
location.reload();
|
||||
});
|
||||
|
||||
startListening();
|
||||
}
|
||||
|
||||
async function startListening() {
|
||||
const statusLabel = document.getElementById('statusLabel');
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://${BASE_URL}/${currentTopic}/json`, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${NTFY_TOKEN}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
statusLabel.innerText = "ERRORE TOKEN";
|
||||
statusLabel.style.color = "red";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) throw new Error("Errore connessione");
|
||||
|
||||
statusLabel.innerText = "ONLINE";
|
||||
statusLabel.style.color = "#28a745";
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
|
||||
while (true) {
|
||||
const { value, done } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
const chunk = decoder.decode(value);
|
||||
const lines = chunk.split('\n');
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.trim()) continue;
|
||||
try {
|
||||
const data = JSON.parse(line);
|
||||
if (data.event === 'message' && data.message) {
|
||||
const match = data.message.match(OTP_REGEX);
|
||||
if (match) handleOTP(match[1]);
|
||||
}
|
||||
} catch (e) { console.error("Errore parsing JSON", e); }
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
statusLabel.innerText = "RE-CONNECTING...";
|
||||
statusLabel.style.color = "orange";
|
||||
setTimeout(startListening, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function handleOTP(newOtp) {
|
||||
document.getElementById('lastCodeLabel').innerText = newOtp;
|
||||
GM_setClipboard(newOtp);
|
||||
|
||||
// Notifica di sistema
|
||||
GM_notification({
|
||||
title: "OTP Infocert",
|
||||
text: `Codice: ${newOtp} (Copiato)`,
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
// Se la modalità è "Digita", prova a inserirlo nel primo campo input vuoto trovato
|
||||
if (document.querySelector('input[name="otpMode"]:checked').value === 'type') {
|
||||
const otpInput = document.querySelector('input[type="text"], input[maxlength="8"]');
|
||||
if (otpInput) {
|
||||
otpInput.value = newOtp;
|
||||
otpInput.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (document.readyState === "complete" || document.readyState === "interactive") {
|
||||
injectInterface();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", injectInterface);
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,14 @@
|
||||
// ==UserScript==
|
||||
// @name OTP Portale Automobilista, Multi-Tab OK require
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 4.4
|
||||
// @description Versione ottimizzata per evitare notifiche multiple con più schede aperte
|
||||
// @author Gemini
|
||||
// @match *://www.ilportaledellautomobilista.it/*
|
||||
// @connect dati-web.it
|
||||
// @connect umctv.altervista.org
|
||||
// @require https://umctv.altervista.org/Scripts/OTP_Multi-Tab.js
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @grant GM_notification
|
||||
// @grant GM_setClipboard
|
||||
// ==/UserScript==
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const API_URL = "https://umctv.altervista.org/hook/OTP.php";
|
||||
const POLLING_RATE = 8000;
|
||||
|
||||
function injectInterface() {
|
||||
const logo = document.getElementById('logo-portale');
|
||||
if (!logo) {
|
||||
setTimeout(injectInterface, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentLink = logo.closest('a');
|
||||
const anchorPoint = parentLink ? parentLink : logo;
|
||||
|
||||
if (document.getElementById('otp-embedded-panel')) return;
|
||||
|
||||
const navPanel = document.createElement('div');
|
||||
navPanel.id = "otp-embedded-panel";
|
||||
navPanel.style = `
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
margin-left: 300px;
|
||||
margin-top: 25px;
|
||||
padding: 0 10px;
|
||||
background: #ffffff;
|
||||
border: 1px dashed #0056b3;
|
||||
border-radius: 4px;
|
||||
vertical-align: middle;
|
||||
height: 56px;
|
||||
font-family: Arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
`;
|
||||
|
||||
navPanel.innerHTML = `
|
||||
<div style="font-size: 10px; font-weight: bold; color: #0056b3; line-height: 1; text-align: center;">OTP<br>LOG</div>
|
||||
<input type="password" id="authCode" placeholder="Secret" style="width: 85px; height: 20px; padding: 2px; border: 1px solid #ccc; border-radius: 2px; font-size: 10px; margin: 0; cursor: text;">
|
||||
<div style="display: flex; flex-direction: column; gap: 1px;">
|
||||
<button id="saveBtn" title="Salva Secret" style="padding: 1px 4px; background: #007bff; color: white; border: none; border-radius: 2px; cursor: pointer; font-size: 8px; height: 11px; line-height: 1;">S</button>
|
||||
<button id="resetBtn" title="Reset Dati" style="padding: 1px 4px; background: #6c757d; color: white; border: none; border-radius: 2px; cursor: pointer; font-size: 8px; height: 11px; line-height: 1;">R</button>
|
||||
</div>
|
||||
<div style="border-left: 1px solid #ddd; height: 20px; margin: 0 4px;"></div>
|
||||
<div style="text-align: center; min-width: 70px;">
|
||||
<div id="lastCodeLabel" style="font-size: 13px; font-weight: bold; color: #d9534f; line-height: 1;">---</div>
|
||||
<div id="statusLabel" style="font-size: 7px; color: #28a745; font-weight: bold; text-transform: uppercase;">In ascolto</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling);
|
||||
startMonitoring();
|
||||
}
|
||||
|
||||
function startMonitoring() {
|
||||
const authInput = document.getElementById('authCode');
|
||||
const statusLabel = document.getElementById('statusLabel');
|
||||
const lastCodeLabel = document.getElementById('lastCodeLabel');
|
||||
|
||||
authInput.value = localStorage.getItem('otp_secret_vault') || "";
|
||||
|
||||
// Carichiamo l'ultimo OTP dal localStorage (condiviso tra tab)
|
||||
let lastOtp = localStorage.getItem('last_detected_otp') || "";
|
||||
if (lastOtp) {
|
||||
lastCodeLabel.innerText = lastOtp;
|
||||
}
|
||||
|
||||
function checkOTP() {
|
||||
const secret = localStorage.getItem('otp_secret_vault');
|
||||
if (!secret || secret.length <= 4) {
|
||||
statusLabel.innerText = "Inactive(NoSecret)";
|
||||
statusLabel.style.color = "#f0ad4e";
|
||||
return;
|
||||
}
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: `${API_URL}?codice=${encodeURIComponent(secret)}`,
|
||||
timeout: 4000,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
const match = data.sms.match(/\d{8}/);
|
||||
|
||||
if (match) {
|
||||
const currentOtp = match[0];
|
||||
|
||||
// Controllo critico: leggiamo il valore aggiornato globalmente
|
||||
const globalLastOtp = localStorage.getItem('last_detected_otp');
|
||||
|
||||
if (currentOtp !== globalLastOtp) {
|
||||
// Questa tab ha rilevato il nuovo codice per prima!
|
||||
localStorage.setItem('last_detected_otp', currentOtp);
|
||||
|
||||
lastCodeLabel.innerText = currentOtp;
|
||||
GM_setClipboard(currentOtp);
|
||||
statusLabel.innerText = "Copiato!";
|
||||
statusLabel.style.color = "#007bff";
|
||||
|
||||
GM_notification({
|
||||
title: "OTP Ricevuto!",
|
||||
text: `codice ${currentOtp} copiato negli appunti.`,
|
||||
timeout: 3000
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
statusLabel.innerText = "In ascolto";
|
||||
statusLabel.style.color = "#28a745";
|
||||
}, 4000);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Listener per aggiornare l'interfaccia se un'altra tab riceve l'OTP
|
||||
window.addEventListener('storage', (e) => {
|
||||
if (e.key === 'last_detected_otp' && e.newValue) {
|
||||
lastCodeLabel.innerText = e.newValue;
|
||||
statusLabel.innerText = "Aggiornato";
|
||||
setTimeout(() => {
|
||||
statusLabel.innerText = "In ascolto";
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('saveBtn').addEventListener('click', (e) => {
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
localStorage.setItem('otp_secret_vault', authInput.value);
|
||||
statusLabel.innerText = "Salvato!";
|
||||
setTimeout(() => { statusLabel.innerText = "In ascolto"; }, 1500);
|
||||
});
|
||||
|
||||
document.getElementById('resetBtn').addEventListener('click', (e) => {
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
localStorage.removeItem('otp_secret_vault');
|
||||
localStorage.removeItem('last_detected_otp');
|
||||
authInput.value = "";
|
||||
lastCodeLabel.innerText = "---";
|
||||
statusLabel.innerText = "Reset";
|
||||
statusLabel.style.color = "#dc3545";
|
||||
});
|
||||
|
||||
setInterval(checkOTP, POLLING_RATE);
|
||||
checkOTP();
|
||||
}
|
||||
|
||||
if (document.readyState === "complete" || document.readyState === "interactive") {
|
||||
injectInterface();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", injectInterface);
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,104 @@
|
||||
// ==UserScript==
|
||||
// @name Portaledeltrasporto - Full Automation + PDF Download
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 3.0
|
||||
// @description Ricerca, Procedi e Download automatico PDF rinominati col Telaio
|
||||
// @author Tu
|
||||
// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @grant none
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const TELAIO = 'VR3UPHNE7R5039330';
|
||||
let downloadEseguiti = false; // Per evitare loop di download infiniti
|
||||
|
||||
function clickReactSafe(element) {
|
||||
if (!element) return;
|
||||
const opts = { bubbles: true, cancelable: true, view: window };
|
||||
element.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
element.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
element.click();
|
||||
}
|
||||
|
||||
function setInputReactSafe(input, value) {
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
|
||||
input.focus();
|
||||
setter.call(input, value);
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
input.blur();
|
||||
}
|
||||
|
||||
function gestisciDownload() {
|
||||
if (downloadEseguiti) return;
|
||||
|
||||
// Cerchiamo i link che hanno l'icona download (spesso sono dentro bottoni o link con svg)
|
||||
const righeTabella = document.querySelectorAll('tr');
|
||||
let count = 0;
|
||||
|
||||
righeTabella.forEach((riga) => {
|
||||
const link = riga.querySelector('a, button[class*="download"]');
|
||||
if (link && (link.href || link.onclick || riga.querySelector('svg'))) {
|
||||
count++;
|
||||
downloadEseguiti = true;
|
||||
|
||||
setTimeout(() => {
|
||||
// Prendiamo il nome del documento dalla prima colonna della riga
|
||||
const descrizioneDoc = riga.cells[0]?.innerText.trim().replace(/[/\\?%*:|"<>]/g, '-') || 'Documento';
|
||||
const nomeFile = `${TELAIO}_${descrizioneDoc}.pdf`;
|
||||
|
||||
console.log(`[TM] Scarico: ${nomeFile}`);
|
||||
|
||||
// Se è un link diretto (<a> con href)
|
||||
if (link.href && link.href !== 'javascript:void(0)') {
|
||||
const a = document.createElement('a');
|
||||
a.href = link.href;
|
||||
a.download = nomeFile;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
} else {
|
||||
// Se è un bottone React/Angular che genera il file al volo
|
||||
clickReactSafe(link);
|
||||
}
|
||||
}, count * 1200); // Ritardo progressivo di 1.2s per ogni file
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eseguiAutomazione() {
|
||||
const url = window.location.href;
|
||||
|
||||
// FASE 1: RICERCA
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
if (input && input.value !== TELAIO) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 500);
|
||||
}
|
||||
if (btnTabella) clickReactSafe(btnTabella);
|
||||
}
|
||||
|
||||
// FASE 2: PROCEDI
|
||||
if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) {
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi');
|
||||
if (btnProcedi && !btnProcedi.disabled) clickReactSafe(btnProcedi);
|
||||
}
|
||||
|
||||
// FASE 3: DOWNLOAD NELLA PAGINA DETTAGLIO
|
||||
if (url.includes('dettaglio-istanza')) {
|
||||
gestisciDownload();
|
||||
}
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(() => eseguiAutomazione());
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
setTimeout(eseguiAutomazione, 1000);
|
||||
})();
|
||||
@@ -0,0 +1,392 @@
|
||||
// ==UserScript==
|
||||
// @name Portaledeltrasporto CON MOD AL DOWNLOAD WORKING2- Full Automation v3.3
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 3.5
|
||||
// @description Fix MouseEvent + Remote Hook Integration
|
||||
// @author Tu
|
||||
// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @connect 192.168.1.33
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
let TELAIO = '';
|
||||
let VALORE2 = '0';
|
||||
let taskAttivo = false;
|
||||
let downloadInCorso = false;
|
||||
let completatoLocalmente = false; // Flag per evitare loop dopo il completamento
|
||||
const ENDPOINT_GET = 'http://192.168.1.33/hook/dati2.php';
|
||||
|
||||
function fetchDati_veryold() {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: ENDPOINT_GET,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
if (data.tipo === 'DOC_NRAP' && data.task === 'fare') {
|
||||
// Se è un nuovo telaio, resettiamo il flag di completamento
|
||||
if (TELAIO !== data.valore1) {
|
||||
TELAIO = data.valore1;
|
||||
VALORE2 = data.valore2;
|
||||
completatoLocalmente = false;
|
||||
console.log(`[TM] Nuovo task ricevuto per telaio: ${TELAIO}`);
|
||||
}
|
||||
|
||||
if (!completatoLocalmente) {
|
||||
taskAttivo = true;
|
||||
eseguiAutomazione();
|
||||
}
|
||||
} else {
|
||||
taskAttivo = false;
|
||||
completatoLocalmente = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[TM] Errore parsing dati", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fetchDati_old() {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: ENDPOINT_GET,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
if (data.tipo === 'DOC_NRAP' && data.task === 'fare') {
|
||||
|
||||
// --- LOGICA DI REINDIRIZZAMENTO ---
|
||||
const targetUrl = 'https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze';
|
||||
if (!window.location.href.includes('le-mie-istanze') &&
|
||||
!window.location.href.includes('dettaglio-istanza') &&
|
||||
!window.location.href.includes('/abilitazione/')) {
|
||||
|
||||
console.log("[TM] Nuovo task rilevato, vado alla pagina di ricerca...");
|
||||
window.location.href = targetUrl;
|
||||
return; // Interrompiamo l'esecuzione qui, la pagina cambierà
|
||||
}
|
||||
// ----------------------------------
|
||||
|
||||
if (TELAIO !== data.valore1) {
|
||||
TELAIO = data.valore1;
|
||||
VALORE2 = data.valore2;
|
||||
completatoLocalmente = false;
|
||||
console.log(`[TM] Nuovo task ricevuto per telaio: ${TELAIO}`);
|
||||
}
|
||||
|
||||
if (!completatoLocalmente) {
|
||||
taskAttivo = true;
|
||||
eseguiAutomazione();
|
||||
}
|
||||
} else {
|
||||
taskAttivo = false;
|
||||
completatoLocalmente = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[TM] Errore parsing dati", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fetchDati() {
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: ENDPOINT_GET,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
const targetHome = 'https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze';
|
||||
|
||||
// --- LOGICA DI RESET SPECIFICA ---
|
||||
// if (data.task === 'reset') {
|
||||
if (data.tipo === 'RESET_NRAP') {
|
||||
console.log("[TM] Ricevuto comando RESET. Ritorno alla home e pulizia variabili.");
|
||||
TELAIO = '';
|
||||
VALORE2 = '0';
|
||||
completatoLocalmente = false;
|
||||
taskAttivo = false;
|
||||
|
||||
// Se non siamo già in home, ci spostiamo
|
||||
if (window.location.href !== targetHome) {
|
||||
window.location.href = targetHome;
|
||||
}
|
||||
return; // Esce dalla funzione, non esegue altro
|
||||
}
|
||||
// ---------------------------------
|
||||
|
||||
if (data.tipo === 'DOC_NRAP' && data.task === 'fare') {
|
||||
// Se il telaio cambia mentre siamo operativi, forziamo il redirect
|
||||
if (TELAIO !== '' && TELAIO !== data.valore1) {
|
||||
console.log(`[TM] Cambio telaio rilevato (${TELAIO} -> ${data.valore1}). Redirect.`);
|
||||
TELAIO = data.valore1;
|
||||
window.location.href = targetHome;
|
||||
return;
|
||||
}
|
||||
|
||||
// Aggiornamento dati task
|
||||
if (TELAIO !== data.valore1) {
|
||||
TELAIO = data.valore1;
|
||||
VALORE2 = data.valore2;
|
||||
completatoLocalmente = false;
|
||||
}
|
||||
|
||||
if (!completatoLocalmente) {
|
||||
taskAttivo = true;
|
||||
eseguiAutomazione();
|
||||
}
|
||||
} else {
|
||||
taskAttivo = false;
|
||||
completatoLocalmente = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[TM] Errore parsing dati", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function segnaComeCompletato_old() {
|
||||
completatoLocalmente = true;
|
||||
taskAttivo = false;
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: ENDPOINT_GET,
|
||||
data: JSON.stringify({ task: "completato", valore1: TELAIO }),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
onload: function() {
|
||||
console.log("[TM] Server aggiornato: task completato.");
|
||||
downloadInCorso = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function segnaComeCompletato() {
|
||||
completatoLocalmente = true;
|
||||
taskAttivo = false;
|
||||
|
||||
// Prepariamo l'oggetto completo con i valori aggiornati
|
||||
const payload = {
|
||||
tipo: "DOC_NRAP",
|
||||
task: "completato", // Unica variabile che cambia davvero
|
||||
valore1: TELAIO,
|
||||
valore2: VALORE2,
|
||||
valore3: "0"
|
||||
};
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: ENDPOINT_GET,
|
||||
data: JSON.stringify(payload),
|
||||
headers: { "Content-Type": "application/json" },
|
||||
onload: function(response) {
|
||||
console.log("[TM] Server aggiornato con tutti i campi. Task: completato.");
|
||||
downloadInCorso = false;
|
||||
},
|
||||
onerror: function(err) {
|
||||
console.error("[TM] Errore nell'invio dei dati al server", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// FIX: Funzione click corretta per evitare l'errore 'view' member
|
||||
function clickReactSafe_OLD(element) {
|
||||
if (!element) return;
|
||||
const opts = { bubbles: true, cancelable: true, view: window.unsafeWindow || window };
|
||||
|
||||
// Se il costruttore standard fallisce, usiamo il metodo più compatibile
|
||||
try {
|
||||
element.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
element.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
element.click();
|
||||
} catch (e) {
|
||||
// Fallback per browser restrittivi
|
||||
element.dispatchEvent(new Event('mousedown', { bubbles: true }));
|
||||
element.dispatchEvent(new Event('mouseup', { bubbles: true }));
|
||||
element.click();
|
||||
}
|
||||
}
|
||||
|
||||
function clickReactSafe(element) {
|
||||
// Se l'elemento non esiste, esci silenziosamente senza generare errori
|
||||
if (!element || typeof element.dispatchEvent !== 'function') {
|
||||
console.warn("[TM] Tentativo di click su un elemento non valido o non trovato.");
|
||||
return;
|
||||
}
|
||||
|
||||
const opts = { bubbles: true, cancelable: true, view: window.unsafeWindow || window };
|
||||
|
||||
try {
|
||||
element.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
element.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
element.click();
|
||||
} catch (e) {
|
||||
element.dispatchEvent(new Event('mousedown', { bubbles: true }));
|
||||
element.dispatchEvent(new Event('mouseup', { bubbles: true }));
|
||||
element.click();
|
||||
}
|
||||
}
|
||||
|
||||
function setInputReactSafe(input, value) {
|
||||
if (!input) return;
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
|
||||
input.focus();
|
||||
setter.call(input, value);
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
function avviaDownloadDocumenti() {
|
||||
if (downloadInCorso) return;
|
||||
|
||||
const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn'));
|
||||
if (tuttiIBottoni.length === 0) return;
|
||||
|
||||
downloadInCorso = true;
|
||||
const titoliGiaVisti = new Set();
|
||||
let delayDoc = 0;
|
||||
|
||||
tuttiIBottoni.forEach((btn, index, array) => {
|
||||
const riga = btn.closest('tr');
|
||||
const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim();
|
||||
|
||||
if (!titoliGiaVisti.has(titolo)) {
|
||||
titoliGiaVisti.add(titolo);
|
||||
|
||||
setTimeout(() => {
|
||||
console.log(`[TM] 1. Avvio Download: ${titolo}`);
|
||||
clickReactSafe(btn);
|
||||
|
||||
// --- SEQUENZA MODALE ---
|
||||
|
||||
// STEP A: Click Esporta File (dopo 1.2 secondi)
|
||||
setTimeout(() => {
|
||||
//const btnEsporta = Array.from(document.querySelectorAll('button.btn-primary.btn-xs'))
|
||||
const btnEsporta = Array.from(document.querySelectorAll('button.btn-primary.btn-xs'));
|
||||
//.find(b => b.textContent.includes('Esporta File'));
|
||||
|
||||
if (btnEsporta) {
|
||||
console.log(`[TM] 2. Click Esporta File per: ${titolo}`);
|
||||
clickReactSafe(btnEsporta);
|
||||
}
|
||||
|
||||
// STEP B: Click Chiudi Modale (dopo altri 1.5 secondi dal click esporta)
|
||||
setTimeout(() => {
|
||||
const btnChiudiModale = document.querySelector('button.ModalContent__header--btn');
|
||||
if (btnChiudiModale) {
|
||||
console.log(`[TM] 3. Chiusura modale per: ${titolo}`);
|
||||
clickReactSafe(btnChiudiModale);
|
||||
}
|
||||
}, 1500);
|
||||
|
||||
}, 1200);
|
||||
// -----------------------
|
||||
|
||||
// Se è l'ultimo documento
|
||||
if (index === array.length - 1) {
|
||||
setTimeout(segnaComeCompletato, 5000); // Aumentato a 5s per sicurezza
|
||||
}
|
||||
}, delayDoc);
|
||||
|
||||
// Aumentiamo il delay totale tra un file e l'altro a 5 secondi
|
||||
// per coprire l'intera sequenza (Download -> Esporta -> Chiudi)
|
||||
delayDoc += 3000;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function avviaDownloadDocumenti_old() {
|
||||
if (downloadInCorso) return;
|
||||
|
||||
const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn'));
|
||||
if (tuttiIBottoni.length === 0) return;
|
||||
|
||||
downloadInCorso = true;
|
||||
const titoliGiaVisti = new Set();
|
||||
let delayDoc = 0;
|
||||
|
||||
tuttiIBottoni.forEach((btn, index, array) => {
|
||||
const riga = btn.closest('tr');
|
||||
const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim();
|
||||
|
||||
if (!titoliGiaVisti.has(titolo)) {
|
||||
titoliGiaVisti.add(titolo);
|
||||
|
||||
setTimeout(() => {
|
||||
console.log(`[TM] Download: ${titolo}`);
|
||||
clickReactSafe(btn);
|
||||
|
||||
// --- NUOVA LOGICA CHIUSURA MODALE ---
|
||||
setTimeout(() => {
|
||||
const btnChiudiModale = document.querySelector('button.ModalContent__header--btn');
|
||||
if (btnChiudiModale) {
|
||||
console.log(`[TM] Chiusura modale per: ${titolo}`);
|
||||
clickReactSafe(btnChiudiModale);
|
||||
}
|
||||
}, 1000); // Aspetta 1 secondo dopo il click di download
|
||||
// ------------------------------------
|
||||
|
||||
// Se è l'ultimo documento unico trovato
|
||||
if (index === array.length - 1) {
|
||||
setTimeout(segnaComeCompletato, 1500);
|
||||
}
|
||||
}, delayDoc);
|
||||
|
||||
// Ho aumentato leggermente il delay tra un file e l'altro (3.5s invece di 2.5s)
|
||||
// per dare tempo alla modale di aprirsi, restare aperta 1s e chiudersi.
|
||||
delayDoc += 1500;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eseguiAutomazione() {
|
||||
if (!taskAttivo || completatoLocalmente) return;
|
||||
|
||||
const url = window.location.href;
|
||||
|
||||
// FASE 1: RICERCA
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
if (input && TELAIO !== '' && input.value !== TELAIO) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800);
|
||||
}
|
||||
if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1500);
|
||||
}
|
||||
|
||||
// FASE 2: PROCEDI
|
||||
if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) {
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi');
|
||||
if (btnProcedi && !btnProcedi.disabled) setTimeout(() => clickReactSafe(btnProcedi), 1000);
|
||||
}
|
||||
|
||||
// FASE 3: DOWNLOAD
|
||||
if (url.includes('dettaglio-istanza')) {
|
||||
if (parseInt(VALORE2) > 0) {
|
||||
if (document.querySelector('button.DocumentsSection__file-btn')) {
|
||||
avviaDownloadDocumenti();
|
||||
}
|
||||
} else {
|
||||
console.log("[TM] Valore2 <= 1, chiusura task senza download.");
|
||||
segnaComeCompletato();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
if (taskAttivo) eseguiAutomazione();
|
||||
});
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
// Polling ogni 4 secondi
|
||||
setInterval(fetchDati, 2500);
|
||||
fetchDati();
|
||||
})();
|
||||
@@ -0,0 +1,86 @@
|
||||
// ==UserScript==
|
||||
// @name Portaledeltrasporto WORKING - Full Automation (SPA Fix)
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 2.5
|
||||
// @description Automazione completa dalla ricerca al tasto Procedi, ottimizzata per React/SPA.
|
||||
// @author Tu
|
||||
// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @grant none
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const TELAIO = 'VR3UPHNE7R5039330';
|
||||
|
||||
// Funzione universale per cliccare in modo che React se ne accorga
|
||||
function clickReactSafe(element) {
|
||||
if (!element) return;
|
||||
console.log('[TM] Clicco elemento:', element.textContent.trim() || 'Bottone Azione');
|
||||
|
||||
const opts = { bubbles: true, cancelable: true, view: window };
|
||||
element.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
element.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
element.click();
|
||||
}
|
||||
|
||||
function setInputReactSafe(input, value) {
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
|
||||
input.focus();
|
||||
setter.call(input, value);
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
input.blur();
|
||||
}
|
||||
|
||||
// LOGICA PRINCIPALE
|
||||
function eseguiAutomazione() {
|
||||
const url = window.location.href;
|
||||
|
||||
// --- FASE 1: RICERCA ---
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
// Se c'è l'input e non è ancora stato scritto il telaio
|
||||
if (input && input.value !== TELAIO) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
console.log('[TM] Telaio inserito');
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 500);
|
||||
}
|
||||
|
||||
// Se appare il bottone nella tabella, cliccalo
|
||||
if (btnTabella) {
|
||||
clickReactSafe(btnTabella);
|
||||
}
|
||||
}
|
||||
|
||||
// --- FASE 2: PROCEDI ---
|
||||
if (url.includes('/abilitazione/')) {
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button'))
|
||||
.find(b => b.textContent.trim() === 'Procedi');
|
||||
|
||||
if (btnProcedi && !btnProcedi.disabled) {
|
||||
clickReactSafe(btnProcedi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IL SEGRETO PER LE SPA: Osserva i cambiamenti del DOM
|
||||
// Invece di refreshare, lo script si accorge se appaiono nuovi pezzi di pagina
|
||||
const observer = new MutationObserver(() => {
|
||||
eseguiAutomazione();
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Primo avvio
|
||||
setTimeout(eseguiAutomazione, 1000);
|
||||
|
||||
console.log('[TM] Monitoraggio SPA attivo...');
|
||||
})();
|
||||
@@ -0,0 +1,104 @@
|
||||
// ==UserScript==
|
||||
// @name Portaledeltrasporto WORKING2- Full Automation v3.2
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 3.2
|
||||
// @description Automazione completa con filtro duplicati e selettore classe documenti
|
||||
// @author Tu
|
||||
// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @grant none
|
||||
// @run-at document-end
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const TELAIO = 'VF1RJB00675897644';
|
||||
let downloadInCorso = false;
|
||||
|
||||
function clickReactSafe(element) {
|
||||
if (!element) return;
|
||||
const opts = { bubbles: true, cancelable: true, view: window };
|
||||
element.dispatchEvent(new MouseEvent('mousedown', opts));
|
||||
element.dispatchEvent(new MouseEvent('mouseup', opts));
|
||||
element.click();
|
||||
}
|
||||
|
||||
function setInputReactSafe(input, value) {
|
||||
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
|
||||
input.focus();
|
||||
setter.call(input, value);
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
|
||||
function avviaDownloadDocumenti() {
|
||||
if (downloadInCorso) return;
|
||||
|
||||
// Seleziona i bottoni con la classe specifica indicata
|
||||
const tuttiIBottoni = Array.from(document.querySelectorAll('button.DocumentsSection__file-btn'));
|
||||
|
||||
if (tuttiIBottoni.length === 0) return;
|
||||
|
||||
downloadInCorso = true;
|
||||
const titoliGiaVisti = new Set();
|
||||
let delayDoc = 0;
|
||||
|
||||
console.log(`[TM] Analisi documenti per classe DocumentsSection__file-btn...`);
|
||||
|
||||
tuttiIBottoni.forEach((btn) => {
|
||||
// Risaliamo alla riga o al contenitore per leggere il testo descrittivo
|
||||
// Solitamente il testo è nel primo elemento della riga (td) o in un elemento precedente
|
||||
const riga = btn.closest('tr');
|
||||
const titolo = riga ? riga.innerText.trim().split('\t')[0] : btn.innerText.trim();
|
||||
|
||||
if (!titoliGiaVisti.has(titolo)) {
|
||||
titoliGiaVisti.add(titolo);
|
||||
|
||||
setTimeout(() => {
|
||||
console.log(`[TM] Scaricamento unico: ${titolo}`);
|
||||
clickReactSafe(btn);
|
||||
}, delayDoc);
|
||||
|
||||
delayDoc += 2500; // 2.5 secondi tra un download e l'altro
|
||||
} else {
|
||||
console.log(`[TM] Salto duplicato: ${titolo}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function eseguiAutomazione() {
|
||||
const url = window.location.href;
|
||||
|
||||
// FASE 1: RICERCA
|
||||
if (url.includes('le-mie-istanze')) {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
const btnCerca = Array.from(document.querySelectorAll('button')).find(b => b.textContent.includes('Cerca'));
|
||||
const btnTabella = document.querySelector('button.action-button-table');
|
||||
|
||||
if (input && input.value !== TELAIO) {
|
||||
setInputReactSafe(input, TELAIO);
|
||||
setTimeout(() => { if(btnCerca) clickReactSafe(btnCerca); }, 800);
|
||||
}
|
||||
if (btnTabella) setTimeout(() => clickReactSafe(btnTabella), 1200);
|
||||
}
|
||||
|
||||
// FASE 2: PROCEDI
|
||||
if (url.includes('/abilitazione/') && !url.includes('dettaglio-istanza')) {
|
||||
const btnProcedi = Array.from(document.querySelectorAll('button')).find(b => b.textContent.trim() === 'Procedi');
|
||||
if (btnProcedi && !btnProcedi.disabled) setTimeout(() => clickReactSafe(btnProcedi), 1000);
|
||||
}
|
||||
|
||||
// FASE 3: DOWNLOAD (Dettaglio)
|
||||
if (url.includes('dettaglio-istanza')) {
|
||||
// Verifichiamo che i bottoni siano effettivamente presenti nel DOM
|
||||
if (document.querySelector('button.DocumentsSection__file-btn')) {
|
||||
avviaDownloadDocumenti();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const observer = new MutationObserver(() => eseguiAutomazione());
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
setTimeout(eseguiAutomazione, 2000);
|
||||
})();
|
||||
@@ -0,0 +1,91 @@
|
||||
// ==UserScript==
|
||||
// @name Pulsante NRAP Convalida - Footer
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.0
|
||||
// @description Inserisce il pulsante "Convalida" nell'header blu, allineato a destra
|
||||
// @author Gemini+Gatto.
|
||||
// @match *://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function injectButtonInHeader() {
|
||||
// 1. Cerchiamo l'header blu (HeaderComponent)
|
||||
const header = document.querySelector('header.HeaderComponent');
|
||||
|
||||
// 2. Cerchiamo il pulsante originale nel footer per sapere se dobbiamo mostrare il nostro
|
||||
const allButtons = document.querySelectorAll('footer button, .FooterNavComponent button');
|
||||
let originalBtn = null;
|
||||
for (let btn of allButtons) {
|
||||
if (btn.textContent.toLowerCase().includes('convalida')) {
|
||||
originalBtn = btn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const existingBtn = document.querySelector('#quick-convalida-header');
|
||||
|
||||
// Se non c'è il tasto originale nel footer, nascondiamo il nostro
|
||||
if (!originalBtn) {
|
||||
if (existingBtn) existingBtn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Se l'header esiste e il tasto non c'è ancora, lo creiamo
|
||||
if (header && !existingBtn) {
|
||||
// Rendiamo l'header "relative" per poter posizionare il tasto "absolute" dentro di esso
|
||||
header.style.position = 'relative';
|
||||
|
||||
const btn = document.createElement('button');
|
||||
btn.id = 'quick-convalida-header';
|
||||
btn.innerHTML = '✅ CONVALIDA DOCUMENTAZIONE';
|
||||
|
||||
// STILE: Posizionato a destra, dentro la zona blu
|
||||
btn.style.cssText = `
|
||||
position: absolute;
|
||||
right: 56px; /* Distanza dal bordo destro */
|
||||
top: 78%; /* Centratura verticale rispetto all'header */
|
||||
transform: translateY(-50%);
|
||||
padding: 8px 20px;
|
||||
background-color: #28a745; /* Verde che stacca sul blu */
|
||||
color: white;
|
||||
border: 1px solid #ffffff;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
z-index: 9999;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||
white-space: nowrap;
|
||||
`;
|
||||
|
||||
// Azione al click
|
||||
btn.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
// Ricerchiamo il tasto originale "fresco" nel footer
|
||||
const target = Array.from(document.querySelectorAll('footer button'))
|
||||
.find(b => b.textContent.toLowerCase().includes('convalida'));
|
||||
if (target) {
|
||||
console.log("Tampermonkey: Clicco Convalida originale...");
|
||||
target.click();
|
||||
} else {
|
||||
alert("Pulsante originale non trovato nel footer!");
|
||||
}
|
||||
};
|
||||
|
||||
header.appendChild(btn);
|
||||
} else if (existingBtn) {
|
||||
// Se esiste già, assicuriamoci che sia visibile
|
||||
existingBtn.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// Monitoraggio continuo per gestire i cambi pagina di React
|
||||
const observer = new MutationObserver(injectButtonInHeader);
|
||||
observer.observe(document.body, { childList: true, subtree: true });
|
||||
|
||||
setInterval(injectButtonInHeader, 1000);
|
||||
injectButtonInHeader();
|
||||
})();
|
||||
@@ -0,0 +1,44 @@
|
||||
// ==UserScript==
|
||||
// @name Riempimento Automatico Telaio - Portale Trasporto
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.3
|
||||
// @description Inserimento automatico del numero telaio con gestione metadata avanzata
|
||||
// @author Tu
|
||||
// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/*
|
||||
// @icon https://www.google.com/s2/favicons?sz=64&domain=ilportaledeltrasporto.it
|
||||
// @grant none
|
||||
// @run-at document-end
|
||||
// @noframes
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function inserisciTelaio() {
|
||||
const inputTelaio = document.getElementById('numeroTelaio');
|
||||
|
||||
if (inputTelaio) {
|
||||
alert("✅ Campo trovato! Ora provo a inserire il valore.");
|
||||
// Mettiamo il focus sul campo (simula il click dell'utente)
|
||||
//inputTelaio.focus();
|
||||
|
||||
// Inseriamo il valore
|
||||
inputTelaio.value = 'WAUZZZFU8SN090884';
|
||||
|
||||
// Eventi necessari per far capire ai framework moderni (Angular/React) che il valore è cambiato
|
||||
// inputTelaio.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
// inputTelaio.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
// Togliamo il focus
|
||||
// inputTelaio.blur();
|
||||
|
||||
console.log("Metadata applicati e Telaio inserito.");
|
||||
} else {
|
||||
// Riprova se il caricamento della SPA è lento
|
||||
setTimeout(inserisciTelaio, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Avvio della logica
|
||||
inserisciTelaio();
|
||||
})();
|
||||
@@ -0,0 +1,44 @@
|
||||
// ==UserScript==
|
||||
// @name Riempimento Telaio LE MIE ISTANZE - Focus Avanzato
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 1.5
|
||||
// @description Inserisce il telaio simulando l'interazione mouse/tastiera
|
||||
// @author Tu
|
||||
// @match https://www.ilportaledeltrasporto.it/nove/gestioneistanzanove/spa/le-mie-istanze*
|
||||
// @grant none
|
||||
// @run-at document-end
|
||||
// @noframes
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function inserisciConFocus() {
|
||||
const input = document.getElementById('numeroTelaio');
|
||||
|
||||
if (input) {
|
||||
// 1. Simula il click del mouse per attivare i listener del sito (data-focus-mouse)
|
||||
input.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
|
||||
input.dispatchEvent(new MouseEvent('mouseup', { bubbles: true }));
|
||||
input.click();
|
||||
input.focus();
|
||||
|
||||
// 2. Inserisce il valore
|
||||
input.value = 'WAUZZZFU8SN090884';
|
||||
|
||||
// 3. Simula la digitazione per i framework (Angular/React/Vue)
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
// 4. Simula l'uscita dal campo (spesso abilita il tasto Cerca)
|
||||
input.dispatchEvent(new Event('blur', { bubbles: true }));
|
||||
|
||||
console.log("Inserimento completato con simulazione focus.");
|
||||
} else {
|
||||
setTimeout(inserisciConFocus, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// Un piccolo ritardo iniziale per lasciare che il sito carichi i suoi script
|
||||
setTimeout(inserisciConFocus, 1500);
|
||||
})();
|
||||
@@ -0,0 +1,117 @@
|
||||
// ==UserScript==
|
||||
// @name Robot WORKING Portale - FIX CONNESSIONE
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @description Inserimento, Estrazione Tabella e invio a PHP per Firebird
|
||||
// @version 3.3
|
||||
// @match *://www.ilportaledellautomobilista.it/immatricolazioni/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @connect 192.168.1.33
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const ENDPOINT_GET = "http://192.168.1.33/hook/dati4.php";
|
||||
const ENDPOINT_POST = "http://192.168.1.33/hook/ans4.php";
|
||||
const TARGET_HOME = "https://www.ilportaledellautomobilista.it/immatricolazioni/certificatoConformitaDatiTecniciVE/Read_initAction.action?pageStatus=SEARCH";
|
||||
|
||||
let completatoLocalmente = false;
|
||||
|
||||
console.log("[TM] Inizio monitoraggio...");
|
||||
|
||||
const clean = (val) => (val === "." || !val) ? "" : val.toString().trim();
|
||||
|
||||
function fetchDati() {
|
||||
if (completatoLocalmente) return;
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "GET",
|
||||
url: ENDPOINT_GET,
|
||||
nocache: true,
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
|
||||
if (data.tipo === 'DATI_COC' && data.task === 'fare') {
|
||||
// CONTROLLO FONDAMENTALE: C'è la tabella risultati?
|
||||
const tabella = document.getElementById('listTable');
|
||||
|
||||
if (tabella) {
|
||||
// Se c'è la tabella, estraiamo e chiudiamo il task sul DB
|
||||
completatoLocalmente = true;
|
||||
estraiESalva(data.valore1);
|
||||
}
|
||||
else if (window.location.href.includes("pageStatus=SEARCH") || window.location.href.endsWith("Read_initAction.action")) {
|
||||
// Se siamo nel form e NON c'è ancora la tabella, compiliamo e clicchiamo
|
||||
inserisciDati(data);
|
||||
}
|
||||
}
|
||||
} catch (e) { console.error("Errore JSON", e); }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function inserisciDati(d) {
|
||||
// Evitiamo click multipli se abbiamo già cliccato in questa sessione
|
||||
if (window.alreadyClicked) return;
|
||||
|
||||
console.log("[TM] Compilazione form...");
|
||||
const mappa = {
|
||||
"VEFrom.descrizioneFamigliaVeicolo": d.valore1,
|
||||
"VEFrom.descrizioneVarianteVeicolo": d.valore2,
|
||||
"VE.codiceOmologazioneEuropea": d.valore3,
|
||||
"VE.codiceMarchioVeicolo": d.valore4,
|
||||
"progressivoCostruttoreVeicolo": d.valore5
|
||||
};
|
||||
|
||||
let trovato = false;
|
||||
Object.keys(mappa).forEach(key => {
|
||||
let input = document.querySelector(`input[name*="${key}"]`);
|
||||
if (input) {
|
||||
input.value = clean(mappa[key]);
|
||||
trovato = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (trovato) {
|
||||
const btn = document.getElementById('RicercaCertificatoConformitaDatiTecniciVE_button_value_searchElement');
|
||||
if (btn) {
|
||||
console.log("[TM] Click Ricerca!");
|
||||
window.alreadyClicked = true;
|
||||
btn.click();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function estraiESalva(v1) {
|
||||
console.log("[TM] Tabella trovata. Invio dati al DB...");
|
||||
const rows = document.querySelectorAll('#listTable tbody tr');
|
||||
let risultati = [];
|
||||
|
||||
rows.forEach(row => {
|
||||
const celle = Array.from(row.querySelectorAll('td'))
|
||||
.filter(td => !td.querySelector('input[type="radio"]'))
|
||||
.map(td => td.innerText.trim());
|
||||
if (celle.length > 0) risultati.push(celle);
|
||||
});
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: "POST",
|
||||
url: ENDPOINT_POST,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
data: JSON.stringify({
|
||||
tipo: "SALVATAGGIO_DB",
|
||||
task: "COMPLETATO",
|
||||
riferimento: v1,
|
||||
tabella_dati: risultati
|
||||
}),
|
||||
onload: function() {
|
||||
console.log("[TM] Task inviato al server. Torno alla Home.");
|
||||
// Aspettiamo 2 secondi per sicurezza prima di tornare alla home
|
||||
setTimeout(() => { window.location.href = TARGET_HOME; }, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setInterval(fetchDati, 3000);
|
||||
})();
|
||||
Reference in New Issue
Block a user