1(function() { 2 const currentScriptSrc = document.currentScript.src 3 4 window.addEventListener('load', async (event) => { 5 6 const version = '0.17.2'; 7 const libraryUrl = `https://cdn.jsdelivr.net/npm/c2pa@${version}/+esm`; 8 const { createC2pa, selectProducer, selectEditsAndActivity, selectSocialAccounts } = await import(libraryUrl); 9 // cc-shadow.css and cr.svg must be beside this script 10 const styleLocation = new URL('cc-shadow.css?v=3', currentScriptSrc); 11 const iconSvgLocation = new URL('cr.svg', currentScriptSrc) 12 13 const c2pa = await createC2pa({ 14 wasmSrc: `https://cdn.jsdelivr.net/npm/c2pa@${version}/dist/assets/wasm/toolkit_bg.wasm`, 15 workerSrc: `https://cdn.jsdelivr.net/npm/c2pa@${version}/dist/c2pa.worker.min.js`, 16 downloaderOptions: { inspectSize: 65536 } 17 }); 18 19 processImagesContainers(document.querySelectorAll('.wp-caption:not(.cc-processed), .cc-featured-image-container:not(.cc-processed)')); 20 21 function processImagesContainers(imageContainers) { 22 23 for (var imageContainer of imageContainers) { 24 25 const src = imageContainer?.querySelector('img')?.src 26 27 if (!src || !(new URL(src).hostname.includes('pixelstream.net'))) { 28 continue 29 } 30 31 // this is an async operation. We don't use await to fetch credentials in parallel 32 getImageContentCredentials(imageContainer, src); 33 } 34 } 35 36 window.CONTENT_CREDENTIALS = { 37 processImagesContainers 38 } 39 40 async function getImageContentCredentials(imageContainer, imageSrc) { 41 42 const activeManifest = await getContentCredentials(c2pa, imageSrc); 43 44 if (activeManifest) { 45 46 imageContainer.classList.add('cc-processed') 47 const container = document.createElement('div') 48 container.classList.add('cc-container') 49 50 const shadow = container.attachShadow({ mode: 'open', delegatesFocus: true }); 51 const styleLink = document.createElement('link'); 52 styleLink.setAttribute('rel', 'stylesheet'); 53 styleLink.setAttribute('href', styleLocation.href); 54 shadow.appendChild(styleLink) 55 56 const producer = selectProducer(activeManifest)?.name; 57 const editsAndActivity = await selectEditsAndActivity(activeManifest, 'es-ES', 'light'); 58 const socialAccounts = await selectSocialAccounts(activeManifest); 59 const title = activeManifest?.title || ''; 60 const signature = activeManifest?.signatureInfo || ''; 61 const claimGenerator = activeManifest?.claimGenerator?.split('/')[0].replaceAll('_', ' ') || ""; 62 63 const crButton = createCrIconButton(); 64 shadow.appendChild(crButton); 65 66 const tooltip = createTooltip(); 67 shadow.appendChild(tooltip); 68 69 const content = createContent(producer, claimGenerator, editsAndActivity, socialAccounts, title, signature, imageSrc); 70 tooltip.appendChild(content); 71 72 imageContainer.appendChild(container); 73 } 74 } 75 76 function createCrIconButton() { 77 const button = document.createElement('button'); 78 button.classList.add('cc-button'); 79 const icon = document.createElement('img'); 80 icon.classList.add('cc-cricon') 81 icon.setAttribute('src', iconSvgLocation.href); 82 button.appendChild(icon); 83 return button; 84 } 85 86 function createTooltip() { 87 const tooltip = document.createElement('div'); 88 tooltip.classList.add('cc-tooltip'); 89 tooltip.setAttribute('tabindex', 1); 90 tooltip.setAttribute('role', 'tooltip'); 91 tooltip.style.opacity = 0 92 return tooltip; 93 } 94 95 function createContent(producer, claimGenerator, editsAndActivity, socialAccounts, title, signature, url) { 96 const content = document.createElement('div'); 97 content.classList.add('cc-content') 98 99 const headerElement = document.createElement('h2'); 100 headerElement.innerText = 'Credenciales de Contenido'; 101 content.appendChild(headerElement); 102 103 const signatureElement = document.createElement('p'); 104 signatureElement.innerText = `Enviado por ${signature.issuer}`; 105 content.appendChild(signatureElement); 106 107 const timeElement = document.createElement('p'); 108 timeElement.innerText = `Enviado el ${ 109 new Date(signature.time).toLocaleDateString('es-ES', { 110 year: 'numeric', 111 month: 'short', 112 weekday: 'long', 113 day: '2-digit' 114 }) 115 }`; 116 content.appendChild(timeElement); 117 118 const lineElement = document.createElement('div'); 119 lineElement.setAttribute('class', 'cc-line'); 120 content.appendChild(lineElement); 121 122 const appElement = document.createElement('h3'); 123 appElement.innerText = 'Aplicación utilizada'; 124 content.appendChild(appElement); 125 126 const claimGeneratorElement = document.createElement('div'); 127 claimGeneratorElement.innerText = claimGenerator; 128 content.appendChild(claimGeneratorElement); 129 130 if (producer) { 131 const lineElement = document.createElement('div'); 132 lineElement.setAttribute('class', 'cc-line'); 133 content.appendChild(lineElement); 134 135 const appElement = document.createElement('h3'); 136 appElement.innerText = 'Producido por'; 137 content.appendChild(appElement); 138 139 const producerElement = document.createElement('div'); 140 producerElement.innerText = producer; 141 content.appendChild(producerElement); 142 } 143 144 if (socialAccounts?.length > 0) { 145 const lineElement = document.createElement('div'); 146 lineElement.setAttribute('class', 'cc-line'); 147 content.appendChild(lineElement); 148 149 const headerElement = document.createElement('h3'); 150 headerElement.innerText = 'Redes sociales'; 151 content.appendChild(headerElement);
152 socialAccounts.forEach(account => { 153 const accountElement = document.createElement('div'); 154 accountElement.setAttribute('class', 'cc-icon-container'); 155 const accountIcon = document.createElement('img'); 156 accountIcon.setAttribute('src', getSocialIconFromUrl(account['@id'])); 157 accountIcon.setAttribute('class', 'cc-icon'); 158 accountElement.appendChild(accountIcon); 159 const accountLink = document.createElement('a'); 160 accountLink.setAttribute('href', account['@id']); 161 accountLink.setAttribute('target', '_blank'); 162 accountLink.innerText = account.name; 163 accountElement.appendChild(accountLink); 164 content.appendChild(accountElement); 165 }); 166 } 167 168 if (editsAndActivity?.length > 0) { 169 const lineElement = document.createElement('div'); 170 lineElement.setAttribute('class', 'cc-line'); 171 content.appendChild(lineElement); 172 173 const headerElement = document.createElement('h3'); 174 headerElement.innerText = 'Ediciones y actividad'; 175 content.appendChild(headerElement); 176 editsAndActivity.forEach(edit => { 177 console.log(edit); 178 179 const editElement = document.createElement('div'); 180 editElement.setAttribute('class', 'cc-icon-container'); 181 182 if (edit.icon) { 183 const editIcon = document.createElement('img'); 184 editIcon.setAttribute('src', edit.icon); 185 editIcon.setAttribute('class', 'cc-icon'); 186 editElement.appendChild(editIcon); 187 } 188 189 const editLabel = document.createElement('span'); 190 editLabel.innerText = es.selectors.editsAndActivity[edit.id]?.label; 191 editElement.appendChild(editLabel); 192 193 content.appendChild(editElement); 194 195 const descElement = document.createElement('div'); 196 descElement.setAttribute('class', 'cc-desc'); 197 descElement.innerText = es.selectors.editsAndActivity[edit.id]?.description; 198 content.appendChild(descElement); 199 }); 200 } 201 202 const verifyLink = document.createElement('a'); 203 verifyLink.classList.add('cc-verify'); 204 verifyLink.setAttribute('target', '_blank'); 205 verifyLink.setAttribute('href', `https://verify.contentauthenticity.org/inspect?source=${url}`); 206 verifyLink.innerText = 'Inspeccionar'; 207 content.appendChild(verifyLink); 208 209 return content; 210 } 211 212 async function getContentCredentials(c2pa, url) { 213 try { 214 const { manifestStore } = await c2pa.read(url); 215 const activeManifest = manifestStore?.activeManifest; 216 return activeManifest; 217 } catch (err) { 218 console.error('Error reading image:', err); 219 return null; 220 } 221 } 222 223 function getSocialIconFromUrl(url) { 224 if (url.includes('twitter')) { 225 return 'https://biobio.pixelstream.com/assets/social/twitter.svg'; 226 } else if (url.includes('facebook')) { 227 return 'https://biobio.pixelstream.com/assets/social/facebook.svg'; 228 } else if (url.includes('instagram')) { 229 return 'https://biobio.pixelstream.com/assets/social/instagram.svg'; 230 } else { 231 return null; 232 } 233 } 234 235 const es = JSON.parse(`{ 236 "selectors": { 237 "editsAndActivity": { 238 "c2pa.color_adjustments": { 239 "description": "Se han ajustado propiedades como el tono, la saturación, las curvas, las sombras o las luces", 240 "label": "Ediciones de color o exposición" 241 }, 242 "c2pa.converted": { 243 "description": "El formato del recurso fue cambiado", 244 "label": "Recurso convertido" 245 }, 246 "c2pa.created": { 247 "description": "Se ha creado un nuevo archivo o contenido", 248 "label": "Fecha de creación" 249 }, 250 "c2pa.cropped": { 251 "description": "Se han usado herramientas de recorte, lo que reduce o expande el área de contenido visible", 252 "label": "Ediciones de recorte" 253 }, 254 "c2pa.drawing": { 255 "description": "Se han usado herramientas como lápices, pinceles, borradores o herramientas de formas, trazados o bolÃgrafos", 256 "label": "Ediciones de dibujo" 257 }, 258 "c2pa.edited": { 259 "description": "Se han hecho otros cambios", 260 "label": "Otras ediciones" 261 }, 262 "c2pa.filtered": { 263 "description": "Se han usado herramientas como filtros, estilos o efectos para cambiar la apariencia", 264 "label": "Ediciones de filtro o estilo" 265 }, 266 "c2pa.opened": { 267 "description": "Se ha abierto un archivo preexistente", 268 "label": "Abierto" 269 }, 270 "c2pa.orientation": { 271 "description": "Se ha cambiado la posición u orientación (girado, volteado, etc.)", 272 "label": "Ediciones de orientación" 273 }, 274 "c2pa.placed": { 275 "description": "Se ha añadido contenido preexistente a este archivo", 276 "label": "Importado" 277 }, 278 "c2pa.published": { 279 "description": "Imagen recibida y distribuida", 280 "label": "Imagen publicada" 281 }, 282 "c2pa.removed": { 283 "description": "Uno o más recursos fueron quitados del archivo", 284 "label": "Recursos quitado" 285 }, 286 "c2pa.repackaged": { 287 "description": "El recurso fue reempaquetado sin ser procesado", 288 "label": "Recurso reempaquetado" 289 }, 290 "c2pa.resized": { 291 "description": "Se han modificado las dimensiones o el tamaño del ar
291chivo", 292 "label": "Ediciones de cambio de tamaño" 293 }, 294 "c2pa.transcoded": { 295 "description": "Recurso procesado o comprimido para optimizarlo para exhibición", 296 "label": "Recurso procesado" 297 }, 298 "c2pa.unknown": { 299 "description": "Se han realizado otras ediciones o actividades que no se han podido reconocer", 300 "label": "Ediciones o actividad desconocidas" 301 } 302 } 303 } 304 }`); 305 306 }) 307})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.