Aggiunti file javascript

This commit is contained in:
2026-05-12 21:05:35 +02:00
commit 83a8402bb7
20 changed files with 2901 additions and 0 deletions
+189
View File
@@ -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();
})();
+59
View File
@@ -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');
})();
+54
View File
@@ -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);
})();
+118
View File
@@ -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();
})();
+183
View File
@@ -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);
}
})();
+169
View File
@@ -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==
@@ -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);
})();
+91
View File
@@ -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);
})();