Skip to content

Instantly share code, notes, and snippets.

@aborruso
Created September 27, 2026 16:44
Show Gist options
  • Select an option

  • Save aborruso/255f40695c45daecf3e49401cd136ded to your computer and use it in GitHub Desktop.

Select an option

Save aborruso/255f40695c45daecf3e49401cd136ded to your computer and use it in GitHub Desktop.
violent-monkey-albo-comune-palermo.js
// ==UserScript==
// @name Albo Pretorio Palermo - attachment names
// @namespace https://github.com/aborruso/opencli
// @version 0.2.1
// @description Shows the real file name of each attachment on the act pages of the Comune di Palermo (Albo Pretorio, and the deliberations and ordinances archive of the online services portal), instead of "(Acrobat Kb ...)"
// @match https://albopretorio.comune.palermo.it/albopretorio/*
// @match https://servizionline.comune.palermo.it/portcitt/*
// @grant none
// @run-at document-idle
// ==/UserScript==
// Both portals are the same SISPI application. The page links each
// attachment as `viewDocument?col=ALLEGATI&idx=N`, with only its type and size. The file name is in the `content-disposition`
// header of that URL, and the portal answers HEAD with the headers alone.
// The request runs from the page, so it carries the session cookies the
// index depends on. One request at a time: the portal answers bursts with
// HTTP 429, and that blocks the whole site for this address for a while.
(async () => {
const links = [...document.querySelectorAll('a[href*="viewDocument?col=ALLEGATI"]')];
// The attachments sit in a box fixed at 250px, sized for "(Acrobat Kb ...)":
// long names would wrap at every hyphen.
const box = links[0]?.closest('.container-field');
if (box) box.style.width = 'auto';
for (const a of links) {
// Open the attachment in a new tab: the act page is hard to find again.
a.target = '_blank';
let resp;
try {
resp = await fetch(a.href, { method: 'HEAD', credentials: 'same-origin' });
} catch {
continue;
}
if (resp.status === 429) break;
if (!resp.ok || (resp.headers.get('content-type') ?? '').startsWith('text/html')) continue;
const m = /filename\*?=(?:UTF-8'')?"?([^";]+)"?/i.exec(resp.headers.get('content-disposition') ?? '');
if (!m) continue;
const full = decodeURIComponent(m[1].trim());
// The portal appends the act id and the upload date to every name:
// `..._1800989618_20260917.pdf`. Same for all attachments of an act, so drop it.
const name = full.replace(/_\d{6,}_\d{8}(\.[^.]+)$/, '$1');
const label = document.createElement('span');
label.textContent = ` ${name}`;
label.title = full;
label.style.fontWeight = 'bold';
a.insertBefore(label, a.lastChild);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment