let container; const oneOfOnes = [ ['365c7fe2007cd8eff36137f38142d2fef882d7f2121de959999aab2ecfdbc661i0', "Bearable Guy", 25], ['58b7218b03107c25566f05c720d917e3e1dba838a7aa62dca48b5cd15a0315bdi0', "Bird 1", 30], ['d9b5945836405f9561135100377c16f99d0840b7111a41c6ff353a971d55b690i0', "Bird 2", 24], ['1c1aeff53d127cc4dd237b5a43a3dafdff09673c53ace055b74d4973db7fce6di0', "Black and White", 23], ['06e7359fd120eefe9b5798c2355e6a77993eec787d4c6d05e2c01e7ff402a6b8i0', "Christmas", 23], ['a4eb37ad9fb96c8a83dc124ac9fe74885475700b8fc3fca209c1f3116861786ci0', "Gold", 23], ['c78f06a97c60f39567fe9256ba7f311cbbee80360095c50f23c7982db924701ai0', "Harry Potter", 23], ['66d8638ed3102afbc6da515ab70a34ed0a7cafe00ac5687ac5e6b9a594966f8di0', "King", 29], ['f417bbc5dc18cdafedbf3c898448421408130084563a01246090a94e930e4225i0', "Long Ear", 29], ['26386c657081287b40c3464c3109d0dbfef2685c07919482c5b5c9c3a8e36922i0', "Snow Owl", 23], ['4b61a0aad3d332f538059e7c933039bb9181713701f00654c1a50eec4397e573i0', "Steve", 23], ['3c76be763011194e8aaed09efdc844f7164be04aa06af8c1e63bf080474c0bf5i0', "USA", 23], ['929ca1c9d850c1c39d2dd61889d3b85c95f9fadd1ec48311e0e599fe65311e50i0', "Ripple 1", 23], ['8cd54503c025932887a38fb188605867a86790f17a96a180bc44dab7e4711817i0', "Ripple 2", 23], ['7bef50a6cc4ce413542a806d4506c8f00add5bb6781b4353ca2a0b6c6f62d6cei0', "Ripple 3", 23], ['379afb187ca56c3d9b07c39b18665c17c3c66784a705b0e099c875a892bb742fi0', "Ripple 4", 23], ['6e67ff1451ca44b8780f0341ba06d862b3e218f7b1fa83e0465055568f9b442ci0', "Ripple 5", 23] ]; async function loadAndModify() { const result = await processUrl1of1(); const match = result.match; let collectionIndex = result.collectionIndex; // Define constants for ID mapping const MIN_ID = 1112; const MAX_ARRAY_INDEX = oneOfOnes.length - 1; const MAX_ID = MIN_ID + MAX_ARRAY_INDEX; if (match) { // For metadata URLs, extract the exact ID from the URL to display let displayId = collectionIndex; const hashString = window.location.hash; // If this is a hash metadata URL like #metadata/1120.json if (hashString && hashString.includes("metadata")) { const idMatch = hashString.match(/metadata\/(\d+)\.json/); if (idMatch && idMatch[1]) { // Use the EXACT number from the URL for display displayId = parseInt(idMatch[1]); } } // Validate collectionIndex for metadata if (typeof collectionIndex !== 'number' || isNaN(collectionIndex) || collectionIndex < MIN_ID || collectionIndex > MAX_ID) { console.error(`Invalid collectionIndex (${collectionIndex}) from URL for metadata. Expected range [${MIN_ID}-${MAX_ID}]. Halting operation.`); return; } // Calculate array index from collection index (public ID) const arrayIndex = collectionIndex - MIN_ID; const description = `BRC333 cross-chain ${collectionName} One-of-Ones backed by Bitcoin!`; const jsonOutput = { "name": `${collectionName} #${displayId}`, "image": `https://ordinals.com/content/${oneOfOnes[arrayIndex][0].trim()}`, "collection": { "name": `${collectionName}`, "description": `${description}` }, "attributes": [ { "trait_type": "One of One", "value": `${oneOfOnes[arrayIndex][1]}` } ] }; const jsonString = JSON.stringify(jsonOutput, null, 2); displayJsonOutput(jsonString); return; } // --- Canvas Display Logic --- jsonOutputDiv.style.display = 'none'; canvas.style.display = 'block'; // Determine correct array index based on collectionIndex // If collectionIndex is a large value (1112+), assume it's intended as a display ID and convert to array index // Otherwise if it's small (0-17), use it directly as an array index let arrayIndex; if (collectionIndex >= MIN_ID) { // Convert from display ID (1112+) to array index (0+) arrayIndex = collectionIndex - MIN_ID; } else { // Use as direct array index, but ensure it's valid arrayIndex = collectionIndex; } // Final validation to prevent "Cannot read properties of undefined" if (typeof arrayIndex !== 'number' || isNaN(arrayIndex) || arrayIndex < 0 || arrayIndex > MAX_ARRAY_INDEX) { console.warn(`Canvas: Calculated array index (${arrayIndex}) is invalid or out of bounds. Defaulting to 0.`); arrayIndex = 0; } canvas.width = oneOfOnes[arrayIndex][2]; canvas.height = oneOfOnes[arrayIndex][2]; const ctx = canvas.getContext('2d'); if (!ctx) { console.error('Failed to get 2D rendering context for the canvas'); return; } ctx.clearRect(0, 0, canvas.width, canvas.height); const img = new Image(); img.src = `/content/${oneOfOnes[arrayIndex][0].trim()}`; img.onload = () => { if (ctx && canvas) { ctx.drawImage(img, 0, 0, canvas.width, canvas.height); } else { console.error('Canvas context or element became unavailable during image load.'); } }; img.onerror = () => { console.error(`Failed to load image for X-Owl at index ${arrayIndex}: ${img.src}`); if (ctx) { ctx.fillStyle = 'lightgray'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = 'black'; ctx.textAlign = 'center'; ctx.font = '16px Arial'; ctx.fillText('Image failed to load', canvas.width / 2, canvas.height / 2); } }; setFavicon(oneOfOnes[arrayIndex][0].trim()); } /** * Sets the canvas as the favicon * @param {string} id - The id of the ordinal to use as favicon */ async function setFavicon(id) { const url = `/content/${id.trim()}`; const response = await fetch(url); const blob = await response.blob(); const faviconCanvas = document.createElement('canvas'); const ctx = faviconCanvas.getContext('2d'); const img = new Image(); img.onload = () => { faviconCanvas.width = img.width; faviconCanvas.height = img.height; ctx.drawImage(img, 0, 0); const favicon = document.createElement('link'); favicon.rel = 'icon'; favicon.href = faviconCanvas.toDataURL(); document.head.appendChild(favicon); }; img.src = URL.createObjectURL(blob); } /** * Displays JSON output in the designated HTML elements. * @param {string} jsonString - The JSON string to be displayed. */ function displayJsonOutput(jsonString) { const jsonOutputDiv = document.getElementById('jsonOutput'); const jsonTextPre = document.getElementById('jsonText'); if (jsonOutputDiv && jsonTextPre) { jsonTextPre.textContent = jsonString; jsonOutputDiv.style.display = 'block'; } else { console.error('JSON output elements not found in the DOM.'); } } /** * Processes the current URL to extract collection and block information. * @param {string|null} [testingUrl=null] - Optional testing URL. * @returns {Promise} An object containing match, collection, collectionIndex, blockIndex, blk, testing, and jsonId. */ async function processUrl1of1() { const url = window.location.href; const hash = window.location.hash; let collectionIndex = null; let match = null; // Check for metadata pattern in hash (format: #metadata/NNNN.json) const hashMetadataPattern = /#metadata\/(\d+)\.json$/; const hashMetadataMatch = hash.match(hashMetadataPattern); if (hashMetadataMatch && hashMetadataMatch[1]) { const extractedId = hashMetadataMatch[1]; match = hashMetadataMatch; collectionIndex = parseInt(extractedId); return { match, collectionIndex, }; } // If no metadata in hash, try to parse regular numeric hash if (hash) { const hashPattern = /#(\d+)/; const hashMatch = hash.match(hashPattern); if (hashMatch && hashMatch[1]) { collectionIndex = parseInt(hashMatch[1]); } } // If no hash metadata or numeric hash, check URL path for metadata pattern const metadataPattern = /metadata\/(\d+)\.json$/; const metadataUrlMatch = url.match(metadataPattern); if (metadataUrlMatch && metadataUrlMatch[1]) { match = metadataUrlMatch; const metadataIndex = parseInt(metadataUrlMatch[1]); collectionIndex = metadataIndex; } if (!match) { // If not a metadata URL, ensure JSON output is hidden const jsonOutputDiv = document.getElementById('jsonOutput'); if (jsonOutputDiv && jsonOutputDiv.style.display === 'block') { jsonOutputDiv.style.display = 'none'; } } return { match, collectionIndex, }; } const collectionName = "X-Owls"; const canvas = document.getElementById('canvas'); canvas.style.imageRendering = 'pixelated'; const jsonOutputDiv = document.getElementById('jsonOutput'); window.addEventListener('hashchange', () => loadAndModify()); loadAndModify(); window.Logic = { loadAndModify };