Created
May 22, 2024 02:00
-
-
Save dillera/c2caf629f2af8fb81cbcd0309a1b3896 to your computer and use it in GitHub Desktop.
FujiNet Flasher Auto Manifest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cat <<'EOF' > index.html | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>ESP Web Tools with Dynamic Manifest</title> | |
<style> | |
#spinner { | |
display: none; | |
margin-left: 10px; | |
border: 4px solid rgba(0, 0, 0, 0.1); | |
width: 24px; | |
height: 24px; | |
border-radius: 50%; | |
border-left-color: #09f; | |
animation: spin 1s ease infinite; | |
} | |
@keyframes spin { | |
0% { | |
transform: rotate(0deg); | |
} | |
100% { | |
transform: rotate(360deg); | |
} | |
} | |
</style> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js"></script> | |
<script type="module" src="js/install-button.js"></script> | |
<script type="module"> | |
const CORS_PROXY = "https://flasher.6502.fun:8443/"; | |
async function fetchDailyBuilds() { | |
updateStatus("Connecting to GitHub to fetch daily builds..."); | |
try { | |
const response = await fetch(`${CORS_PROXY}https://api.github.com/repos/FujiNetWIFI/fujinet-firmware/releases/tags/nightly`); | |
if (!response.ok) { | |
const errorText = await response.text(); | |
updateStatus(`Failed to fetch builds from GitHub: ${response.status} ${response.statusText}`); | |
console.error("GitHub API request failed:", response.status, response.statusText, errorText); | |
throw new Error("GitHub API request failed"); | |
} | |
const data = await response.json(); | |
const assets = data.assets; | |
updateStatus("Daily builds fetched successfully."); | |
console.log("GitHub API response:", assets); | |
return assets; | |
} catch (error) { | |
updateStatus("Failed to fetch daily builds: " + error.message); | |
console.error("Failed to fetch daily builds:", error); | |
throw error; | |
} | |
} | |
async function fetchAndExtractZip(url, size) { | |
updateStatus("Fetching ZIP file..."); | |
showSpinner(true); | |
console.log("Fetching ZIP file from URL:", url); | |
const response = await fetch(`${CORS_PROXY}${url}`); | |
if (!response.ok) { | |
throw new Error(`Failed to fetch ZIP file: ${response.statusText}`); | |
} | |
const reader = response.body.getReader(); | |
const contentLength = size; | |
let receivedLength = 0; | |
let chunks = []; | |
while (true) { | |
const { done, value } = await reader.read(); | |
if (done) break; | |
chunks.push(value); | |
receivedLength += value.length; | |
updateStatus(`Received ${receivedLength} of ${contentLength} bytes (${Math.round((receivedLength / contentLength) * 100)}%)`); | |
} | |
const blob = new Blob(chunks); | |
console.log("ZIP file fetched. Extracting..."); | |
const zip = await JSZip.loadAsync(blob); | |
console.log("ZIP file extracted:", zip); | |
showSpinner(false); | |
return zip; | |
} | |
async function generateManifest(build) { | |
updateStatus(`Generating manifest for build: ${build.name}`); | |
console.log("Generating manifest for build:", build); | |
const zip = await fetchAndExtractZip(build.browser_download_url, build.size); | |
// Extract release.json from the ZIP file | |
const releaseJsonFile = zip.file('release.json'); | |
if (!releaseJsonFile) { | |
throw new Error("release.json not found in the ZIP file"); | |
} | |
const releaseJsonContent = await releaseJsonFile.async('string'); | |
const releaseData = JSON.parse(releaseJsonContent); | |
console.log("Extracted release.json content:", releaseData); | |
// Derive name from the ZIP filename | |
const zipFilename = build.name; | |
const nameParts = zipFilename.split('-'); | |
const manifestName = `${nameParts[0]}-${nameParts[1]}-${nameParts[2]}`; | |
const manifest = { | |
name: manifestName, | |
version: releaseData.version, | |
builds: [ | |
{ | |
chipFamily: "ESP32", | |
parts: releaseData.files.map(file => ({ | |
path: file.filename, // Use the filename from the release.json directly | |
offset: parseInt(file.offset, 16) | |
})) | |
} | |
] | |
}; | |
console.log("Generated manifest:", JSON.stringify(manifest, null, 2)); // Log the complete manifest for troubleshooting | |
const blob = new Blob([JSON.stringify(manifest)], { type: 'application/json' }); | |
return { url: URL.createObjectURL(blob), name: manifest.name }; | |
} | |
async function createFlashButton(build) { | |
const { url: manifestUrl, name } = await generateManifest(build); | |
const flashButtonsList = document.getElementById('flash-buttons-list'); | |
let existingButton = Array.from(flashButtonsList.children).find( | |
item => item.textContent.includes(name) | |
); | |
if (!existingButton) { | |
const flashButton = document.createElement('button'); | |
flashButton.textContent = `FLASH: ${name}`; | |
flashButton.onclick = () => { | |
const installButton = document.querySelector('esp-web-install-button'); | |
installButton.setAttribute('manifest', manifestUrl); | |
installButton.click(); | |
}; | |
const listItem = document.createElement('li'); | |
listItem.appendChild(flashButton); | |
flashButtonsList.appendChild(listItem); | |
} else { | |
updateStatus(`FLASH button for ${name} already exists.`); | |
} | |
} | |
async function connectToBuild(build) { | |
updateStatus(`Generating FLASH button for build: ${build.name}`); | |
console.log("Generating FLASH button for build:", build); | |
try { | |
await createFlashButton(build); | |
updateStatus(`FLASH button generated for build: ${build.name}`); | |
console.log("FLASH button generated for build:", build); | |
} catch (error) { | |
updateStatus("Failed to generate FLASH button: " + error.message); | |
console.error("Failed to generate FLASH button:", error); | |
} | |
} | |
function displayBuilds(builds) { | |
updateStatus("Displaying builds..."); | |
const buildsList = document.getElementById('builds-list'); | |
buildsList.innerHTML = ''; // Clear any existing content | |
builds.forEach(build => { | |
const listItem = document.createElement('li'); | |
const button = document.createElement('button'); | |
button.textContent = `Prepare ${build.name}`; | |
button.onclick = () => connectToBuild(build); | |
listItem.appendChild(button); | |
buildsList.appendChild(listItem); | |
}); | |
updateStatus("Builds displayed."); | |
} | |
function updateStatus(message) { | |
const statusElement = document.getElementById('status'); | |
statusElement.textContent = message; | |
console.log(message); // Also log to console for debugging | |
} | |
function showSpinner(show) { | |
const spinner = document.getElementById('spinner'); | |
if (show) { | |
spinner.style.display = 'inline-block'; | |
} else { | |
spinner.style.display = 'none'; | |
} | |
} | |
async function start() { | |
try { | |
updateStatus("Starting initialization..."); | |
const builds = await fetchDailyBuilds(); | |
displayBuilds(builds); | |
updateStatus("Initialization complete."); | |
} catch (error) { | |
updateStatus(`Error during initialization: ${error.message}`); | |
console.error("Error during initialization:", error); | |
} | |
} | |
window.onload = start; | |
</script> | |
</head> | |
<body> | |
<h1>ESP Web Tools with Dynamic Manifest</h1> | |
<p id="status">Initializing...</p> | |
<ul id="builds-list"></ul> | |
<hr> | |
<ul id="flash-buttons-list"></ul> | |
<esp-web-install-button manifest=""></esp-web-install-button> | |
<div id="spinner"></div> | |
</body> | |
</html> | |
EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment