alfredlinux.com/download.php

1110 lines
42 KiB
PHP
Raw Normal View History

<?php
/**
* Alfred Linux P2P Download Page
* Browser-based WebTorrent client no client install needed.
* When download completes, users are encouraged to keep seeding.
*/
header('Cache-Control: no-cache, no-store, must-revalidate');
$pageTitle = "Download Alfred Linux — Powered by the People";
$isoName = "alfred-linux-4.0-rc8-amd64.iso"; // Updated when new builds ship
$isoSize = "2.4 GB";
$version = "4.0 RC8";
$torrentURL = "/downloads/{$isoName}.torrent";
$magnetURI = "magnet:?xt=urn:btih:5eedd261364a0975763fc1a24cab433ab598692a&dn=alfred-linux-4.0-rc8-amd64-20260407.iso&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Fopen.stealth.si%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.torrent.eu.org%3A451%2Fannounce&tr=http%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce";
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($pageTitle) ?></title>
<meta name="description" content="Download Alfred Linux via peer-to-peer — directly in your browser. No torrent client needed. Seed to help the community.">
<meta property="og:title" content="Download Alfred Linux — Powered by the People">
<meta property="og:description" content="Download Alfred Linux via P2P — directly in your browser. No torrent client needed. Seed to help the community.">
<meta property="og:url" content="https://alfredlinux.com/download">
<meta property="og:image" content="https://alfredlinux.com/og-image.png">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Download Alfred Linux — Powered by the People">
<meta name="twitter:description" content="Download Alfred Linux via P2P — directly in your browser. No torrent client needed. Seed to help the community.">
<meta name="twitter:image" content="https://alfredlinux.com/og-image.png">
<link rel="canonical" href="https://alfredlinux.com/download">
<link rel="icon" href="/favicon.ico">
<style>
:root {
--bg: #0a0a0f;
--surface: #12121a;
--border: #1e1e2e;
--accent: #6c5ce7;
--accent2: #00cec9;
--gold: #fdcb6e;
--text: #e0e0e0;
--dim: #888;
--success: #00b894;
--danger: #e17055;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
background: var(--bg);
color: var(--text);
min-height: 100vh;
overflow-x: hidden;
}
/* ── Nav ──────────────────────────────────── */
nav {
display: flex; align-items: center; justify-content: space-between;
padding: 1rem 2rem;
border-bottom: 1px solid var(--border);
background: rgba(10,10,15,0.95);
position: sticky; top: 0; z-index: 100;
backdrop-filter: blur(12px);
}
nav .logo { font-size: 1.3rem; font-weight: 700; }
nav .logo span { color: var(--accent); }
nav .links { display: flex; gap: 1.5rem; }
nav .links a { color: var(--dim); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; }
nav .links a:hover { color: var(--text); }
/* ── Hero ─────────────────────────────────── */
.hero {
text-align: center;
padding: 4rem 2rem 2rem;
}
.hero h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 800;
line-height: 1.1;
margin-bottom: 1rem;
}
.hero h1 .glow {
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.hero p {
color: var(--dim);
font-size: 1.15rem;
max-width: 640px;
margin: 0 auto 2rem;
line-height: 1.6;
}
.badge {
display: inline-block;
background: rgba(108,92,231,0.15);
color: var(--accent);
padding: 0.3rem 0.8rem;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 600;
border: 1px solid rgba(108,92,231,0.3);
margin-bottom: 1.5rem;
}
/* ── Download Card ────────────────────────── */
.dl-card {
max-width: 720px;
margin: 0 auto 3rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 2.5rem;
position: relative;
overflow: hidden;
}
.dl-card::before {
content: '';
position: absolute; top: 0; left: 0; right: 0; height: 3px;
background: linear-gradient(90deg, var(--accent), var(--accent2), var(--gold));
}
/* Start state */
#start-section { text-align: center; }
#start-section h2 { font-size: 1.5rem; margin-bottom: 0.5rem; }
#start-section .meta { color: var(--dim); font-size: 0.9rem; margin-bottom: 1.5rem; }
.btn-torrent {
display: inline-flex; align-items: center; gap: 0.5rem;
background: linear-gradient(135deg, var(--accent), #5a4bd1);
color: #fff;
border: none; border-radius: 12px;
padding: 1rem 2.5rem;
font-size: 1.1rem; font-weight: 700;
cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s;
}
.btn-torrent:hover {
transform: translateY(-2px);
box-shadow: 0 8px 30px rgba(108,92,231,0.4);
}
.btn-torrent svg { width: 22px; height: 22px; }
.alt-links {
margin-top: 1rem;
font-size: 0.85rem; color: var(--dim);
}
.alt-links a { color: var(--accent); text-decoration: none; }
.alt-links a:hover { text-decoration: underline; }
.btn-direct {
display: inline-flex; align-items: center; gap: 0.5rem;
background: rgba(255,255,255,0.08);
color: #ccc;
border: 1px solid rgba(255,255,255,0.15); border-radius: 12px;
padding: 0.75rem 2rem;
font-size: 1rem; font-weight: 600;
cursor: pointer; text-decoration: none;
transition: transform 0.15s, background 0.15s;
margin-top: 0.75rem;
}
.btn-direct:hover {
transform: translateY(-1px);
background: rgba(255,255,255,0.12);
color: #fff;
}
.btn-direct svg { width: 18px; height: 18px; }
/* Progress state */
#progress-section { display: none; }
.progress-bar-outer {
width: 100%;
height: 28px;
background: rgba(255,255,255,0.05);
border-radius: 14px;
overflow: hidden;
margin-bottom: 1.5rem;
position: relative;
}
.progress-bar-inner {
height: 100%;
width: 0%;
background: linear-gradient(90deg, var(--accent), var(--accent2));
border-radius: 14px;
transition: width 0.5s ease;
position: relative;
}
.progress-bar-inner::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.15), transparent);
animation: shimmer 2s infinite;
}
@keyframes shimmer { 0%{transform:translateX(-100%)} 100%{transform:translateX(100%)} }
.progress-pct {
position: absolute;
top: 50%; left: 50%; transform: translate(-50%,-50%);
font-weight: 700; font-size: 0.85rem; z-index: 2;
text-shadow: 0 1px 3px rgba(0,0,0,0.5);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.stat-box {
background: rgba(255,255,255,0.03);
border: 1px solid var(--border);
border-radius: 10px;
padding: 0.8rem 1rem;
text-align: center;
}
.stat-box .label { font-size: 0.75rem; color: var(--dim); text-transform: uppercase; letter-spacing: 0.05em; }
.stat-box .value { font-size: 1.3rem; font-weight: 700; margin-top: 0.3rem; }
/* Complete / Seeding state */
#seed-section { display: none; text-align: center; }
.seed-banner {
background: linear-gradient(135deg, rgba(0,184,148,0.1), rgba(108,92,231,0.1));
border: 1px solid rgba(0,184,148,0.3);
border-radius: 16px;
padding: 2.5rem;
margin-bottom: 2rem;
}
.seed-banner h2 {
font-size: 1.8rem;
margin-bottom: 0.5rem;
background: linear-gradient(135deg, var(--success), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.seed-banner p {
color: var(--text);
font-size: 1.1rem;
line-height: 1.6;
max-width: 520px;
margin: 0 auto;
}
.seed-banner .big-msg {
font-size: 1.5rem;
font-weight: 800;
color: var(--gold);
margin-top: 1.5rem;
-webkit-text-fill-color: unset;
}
.seed-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.seed-timer {
font-size: 2.5rem;
font-weight: 800;
font-variant-numeric: tabular-nums;
background: linear-gradient(135deg, var(--gold), var(--accent));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
margin-bottom: 0.5rem;
}
.seed-timer-label { color: var(--dim); font-size: 0.85rem; }
.btn-save {
display: inline-flex; align-items: center; gap: 0.5rem;
background: var(--success);
color: #fff;
border: none; border-radius: 12px;
padding: 0.8rem 2rem;
font-size: 1rem; font-weight: 700;
cursor: pointer;
margin-top: 1rem;
}
.btn-save:hover { opacity: 0.9; }
.share-btn {
display: inline-flex; align-items: center; gap: 0.5rem;
background: rgba(108,92,231,0.15);
color: var(--accent);
border: 1px solid rgba(108,92,231,0.3);
border-radius: 10px;
padding: 0.6rem 1.5rem;
font-size: 0.9rem; font-weight: 600;
cursor: pointer;
margin: 0.5rem;
transition: all 0.2s;
}
.share-btn:hover { background: rgba(108,92,231,0.25); }
/* ── Community Section ────────────────────── */
.community {
max-width: 720px;
margin: 0 auto 4rem;
text-align: center;
}
.community h2 { font-size: 1.8rem; margin-bottom: 1rem; }
.community p { color: var(--dim); max-width: 540px; margin: 0 auto 2rem; line-height: 1.6; }
.swarm-vis {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 2rem;
min-height: 200px;
position: relative;
overflow: hidden;
}
.swarm-vis canvas { width: 100%; height: 200px; }
.swarm-counter {
font-size: 3rem;
font-weight: 800;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
}
.swarm-label { color: var(--dim); font-size: 0.9rem; }
/* ── How It Works ─────────────────────────── */
.how-it-works {
max-width: 720px;
margin: 0 auto 4rem;
padding: 0 2rem;
}
.how-it-works h2 { text-align: center; font-size: 1.5rem; margin-bottom: 2rem; }
.steps {
display: grid; gap: 1.5rem;
}
.step {
display: flex; gap: 1.2rem; align-items: flex-start;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.5rem;
}
.step-num {
width: 36px; height: 36px;
background: linear-gradient(135deg, var(--accent), var(--accent2));
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-weight: 800; font-size: 0.9rem;
flex-shrink: 0;
}
.step h3 { font-size: 1rem; margin-bottom: 0.3rem; }
.step p { color: var(--dim); font-size: 0.9rem; line-height: 1.5; }
/* ── Footer ───────────────────────────────── */
footer {
text-align: center;
padding: 2rem;
border-top: 1px solid var(--border);
color: var(--dim);
font-size: 0.85rem;
}
footer a { color: var(--accent); text-decoration: none; }
/* ── Error state ──────────────────────────── */
.error-box {
display: none;
background: rgba(225,112,85,0.1);
border: 1px solid rgba(225,112,85,0.3);
border-radius: 10px;
padding: 1rem 1.5rem;
margin-top: 1rem;
color: var(--danger);
font-size: 0.9rem;
}
/* ── Flash to USB Guide ────────────────── */
.flash-guide {
max-width: 720px;
margin: 0 auto 3rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 2.5rem;
display: none;
}
.flash-guide.visible { display: block; }
.flash-guide h2 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
text-align: center;
}
.flash-guide .subtitle {
color: var(--dim);
text-align: center;
font-size: 0.95rem;
margin-bottom: 2rem;
}
.flash-tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--border);
padding-bottom: 0.5rem;
}
.flash-tab {
background: none;
border: none;
color: var(--dim);
font-size: 0.9rem;
font-weight: 600;
padding: 0.5rem 1rem;
cursor: pointer;
border-radius: 8px 8px 0 0;
transition: all 0.2s;
}
.flash-tab:hover { color: var(--text); }
.flash-tab.active {
color: var(--accent);
background: rgba(108,92,231,0.1);
border-bottom: 2px solid var(--accent);
}
.flash-panel { display: none; }
.flash-panel.active { display: block; }
.flash-panel h3 {
font-size: 1.1rem;
margin-bottom: 0.8rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.flash-panel ol {
list-style: decimal;
padding-left: 1.5rem;
color: var(--text);
line-height: 2;
font-size: 0.95rem;
}
.flash-panel ol li { margin-bottom: 0.3rem; }
.flash-panel a {
color: var(--accent);
text-decoration: none;
font-weight: 600;
}
.flash-panel a:hover { text-decoration: underline; }
.flash-cmd {
display: flex;
align-items: center;
gap: 0.5rem;
background: rgba(0,0,0,0.4);
border: 1px solid var(--border);
border-radius: 8px;
padding: 0.6rem 1rem;
margin: 0.5rem 0;
font-family: 'SF Mono', 'Fira Code', monospace;
font-size: 0.85rem;
color: var(--accent2);
overflow-x: auto;
}
.flash-cmd code { flex: 1; white-space: nowrap; }
.flash-cmd button {
background: none;
border: 1px solid var(--border);
color: var(--dim);
border-radius: 6px;
padding: 0.3rem 0.6rem;
cursor: pointer;
font-size: 0.75rem;
flex-shrink: 0;
}
.flash-cmd button:hover { color: var(--text); border-color: var(--accent); }
.flash-warn {
background: rgba(253,203,110,0.1);
border: 1px solid rgba(253,203,110,0.25);
border-radius: 8px;
padding: 0.7rem 1rem;
color: var(--gold);
font-size: 0.85rem;
margin-top: 0.8rem;
}
@media (max-width: 600px) {
.dl-card { margin: 0 1rem 3rem; padding: 1.5rem; }
.flash-guide { margin: 0 1rem 3rem; padding: 1.5rem; }
.stats-grid { grid-template-columns: 1fr 1fr; }
nav { padding: 0.8rem 1rem; }
.hero { padding: 2rem 1rem 1rem; }
.flash-tabs { flex-wrap: wrap; }
}
</style>
</head>
<body>
<!-- ── Nav ──────────────────────────────────────── -->
<nav>
<div class="logo">Alfred <span>Linux</span></div>
<div class="links">
<a href="/">Home</a>
<a href="/download" style="color:var(--accent);font-weight:600;">Download</a>
<a href="/apps">Apps</a>
<a href="/docs">Docs</a>
<a href="/releases">Releases</a>
<a href="/security">Security</a>
<a href="/developers">Developers</a>
<a href="/compare">Compare</a>
<a href="/about">About</a>
</div>
</nav>
<!-- ── Hero ─────────────────────────────────────── -->
<section class="hero">
<div class="badge"> Peer-to-Peer · Zero Install · Browser-Native</div>
<h1>Download at the <span class="glow">Speed of the Swarm</span></h1>
<p>No torrent client needed. Your browser IS the client. Every downloader becomes a seeder.<br>
The more people who join, the faster everyone downloads.</p>
</section>
<!-- ── Download Card ───────────────────────────── -->
<div class="dl-card">
<!-- Start -->
<div id="start-section">
<h2>Alfred Linux <?= htmlspecialchars($version) ?></h2>
<div class="meta"><?= htmlspecialchars($isoName) ?> · <?= htmlspecialchars($isoSize) ?> · Debian Trixie 13 · Kernel 7.0.0-rc7 · 16 Hooks · 32 Security Modules · Hardened</div>
<button class="btn-torrent" onclick="startDownload()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 5v14M5 12l7 7 7-7"/></svg>
Start P2P Download
</button>
<div class="alt-links">
<a href="<?= htmlspecialchars($torrentURL) ?>">Download .torrent file</a> (for desktop torrent clients like qBittorrent)
</div>
</div>
<!-- Progress -->
<div id="progress-section">
<div class="progress-bar-outer">
<div class="progress-bar-inner" id="progress-bar"></div>
<div class="progress-pct" id="progress-pct">0%</div>
</div>
<div class="stats-grid">
<div class="stat-box">
<div class="label">Downloaded</div>
<div class="value" id="stat-downloaded">0 MB</div>
</div>
<div class="stat-box">
<div class="label">Speed</div>
<div class="value" id="stat-speed">0 KB/s</div>
</div>
<div class="stat-box">
<div class="label">Peers</div>
<div class="value" id="stat-peers">0</div>
</div>
<div class="stat-box">
<div class="label">ETA</div>
<div class="value" id="stat-eta"></div>
</div>
<div class="stat-box">
<div class="label">Uploaded</div>
<div class="value" id="stat-uploaded">0 MB</div>
</div>
</div>
<p style="color:var(--dim);font-size:0.85rem;text-align:center;">
You're already sharing pieces with other downloaders!
</p>
</div>
<!-- Seed / Complete -->
<div id="seed-section">
<div class="seed-banner">
<h2>🎉 Download Complete!</h2>
<p>Your copy of Alfred Linux is ready. But here's the thing </p>
<p class="big-msg">
The longer you keep this page open,<br>
the faster the new free world is built<br>
with YOUR help!
</p>
</div>
<div class="seed-timer" id="seed-timer">00:00:00</div>
<div class="seed-timer-label">Time you've been seeding for the community</div>
<div class="seed-stats">
<div class="stat-box">
<div class="label">You've Shared</div>
<div class="value" id="seed-uploaded">0 MB</div>
</div>
<div class="stat-box">
<div class="label">Upload Speed</div>
<div class="value" id="seed-speed">0 KB/s</div>
</div>
<div class="stat-box">
<div class="label">Souls Saved</div>
<div class="value" id="seed-peers" style="color:var(--gold);">0</div>
</div>
<div class="stat-box">
<div class="label">Your Ratio</div>
<div class="value" id="seed-ratio">0.00</div>
</div>
</div>
<button class="btn-save" id="save-btn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M12 5v14M5 12l7 7 7-7"/></svg>
Save ISO to Disk
</button>
<div style="margin-top: 2rem;">
<p style="color:var(--dim);font-size:0.9rem;margin-bottom:0.8rem;">Spread the word:</p>
<button class="share-btn" onclick="shareTwitter()">𝕏 Share on X</button>
<button class="share-btn" onclick="shareLink()">🔗 Copy Link</button>
</div>
</div>
<div class="error-box" id="error-box"></div>
</div>
<!-- ── Flash to USB Guide ──────────────────────── -->
<div class="flash-guide" id="flash-guide">
<h2>Flash to USB Drive</h2>
<p class="subtitle">Turn your ISO into a bootable USB stick in minutes</p>
<div class="flash-tabs">
<button class="flash-tab active" onclick="showFlashTab('windows')">Windows</button>
<button class="flash-tab" onclick="showFlashTab('mac')">macOS</button>
<button class="flash-tab" onclick="showFlashTab('linux')">Linux</button>
<button class="flash-tab" onclick="showFlashTab('etcher')">balenaEtcher</button>
</div>
<div class="flash-panel active" id="flash-windows">
<h3>&#x1f4bb; Rufus (Windows)</h3>
<ol>
<li>Download <a href="https://rufus.ie" target="_blank" rel="noopener">Rufus</a> (free, portable, no install needed)</li>
<li>Insert a USB drive (8 GB minimum)</li>
<li>Open Rufus &rarr; select your USB under <strong>Device</strong></li>
<li>Click <strong>SELECT</strong> &rarr; choose the Alfred Linux ISO you just saved</li>
<li>Partition scheme: <strong>GPT</strong> &middot; Target: <strong>UEFI</strong></li>
<li>Click <strong>START</strong> &rarr; wait until &ldquo;READY&rdquo; appears</li>
<li>Reboot your PC and boot from USB (usually F12 / F2 / DEL at startup)</li>
</ol>
</div>
<div class="flash-panel" id="flash-mac">
<h3>&#x1f34e; Terminal (macOS)</h3>
<ol>
<li>Insert a USB drive (8 GB minimum)</li>
<li>Open Terminal and find your USB disk:</li>
</ol>
<div class="flash-cmd"><code>diskutil list</code><button onclick="copyCmd(this)">Copy</button></div>
<ol start="3">
<li>Unmount the USB (replace <strong>diskN</strong> with your disk):</li>
</ol>
<div class="flash-cmd"><code>diskutil unmountDisk /dev/diskN</code><button onclick="copyCmd(this)">Copy</button></div>
<ol start="4">
<li>Flash the ISO (use <strong>rdiskN</strong> for speed):</li>
</ol>
<div class="flash-cmd"><code>sudo dd if=~/Downloads/<?= htmlspecialchars($isoName) ?> of=/dev/rdiskN bs=4m status=progress</code><button onclick="copyCmd(this)">Copy</button></div>
<ol start="5">
<li>Wait until complete, then eject and reboot from USB</li>
</ol>
<div class="flash-warn">&#x26a0;&#xfe0f; Double-check the disk number! <code>dd</code> overwrites the target without confirmation.</div>
</div>
<div class="flash-panel" id="flash-linux">
<h3>&#x1f427; Terminal (Linux)</h3>
<ol>
<li>Insert a USB drive (8 GB minimum)</li>
<li>Find your USB device:</li>
</ol>
<div class="flash-cmd"><code>lsblk</code><button onclick="copyCmd(this)">Copy</button></div>
<ol start="3">
<li>Flash the ISO (replace <strong>/dev/sdX</strong> with your USB &mdash; e.g. /dev/sdb):</li>
</ol>
<div class="flash-cmd"><code>sudo dd if=~/Downloads/<?= htmlspecialchars($isoName) ?> of=/dev/sdX bs=4M status=progress oflag=sync</code><button onclick="copyCmd(this)">Copy</button></div>
<ol start="4">
<li>Wait until complete, then reboot and boot from USB</li>
</ol>
<div class="flash-warn">&#x26a0;&#xfe0f; Make sure <code>/dev/sdX</code> is your USB, not your main drive! Check <code>lsblk</code> output carefully.</div>
</div>
<div class="flash-panel" id="flash-etcher">
<h3>&#x26a1; balenaEtcher (Any OS)</h3>
<ol>
<li>Download <a href="https://etcher.balena.io" target="_blank" rel="noopener">balenaEtcher</a> (free, works on Windows/Mac/Linux)</li>
<li>Open Etcher &rarr; click <strong>Flash from file</strong> &rarr; select the Alfred Linux ISO</li>
<li>Click <strong>Select target</strong> &rarr; choose your USB drive</li>
<li>Click <strong>Flash!</strong> and wait for completion + verification</li>
<li>Reboot and boot from USB</li>
</ol>
<p style="color:var(--dim);font-size:0.85rem;margin-top:1rem;">Etcher is the easiest option if you're not comfortable with command-line tools. It validates the write automatically.</p>
</div>
</div>
<!-- ── Community Swarm ─────────────────────────── -->
<section class="community">
<h2>The Alfred Swarm</h2>
<p>Every dot is a person downloading, seeding, building the future of computing together.</p>
<div class="swarm-vis">
<div class="swarm-counter" id="swarm-count">0</div>
<div class="swarm-label">active peers in the swarm right now</div>
<canvas id="swarm-canvas"></canvas>
</div>
</section>
<!-- ── Integrity Verification ───────────────────── -->
<section class="how-it-works" style="border-top:1px solid var(--border);">
<h2>Verify Your Download</h2>
<p style="color:var(--dim);text-align:center;max-width:700px;margin:0 auto 2rem;line-height:1.6;">
Two independent hash algorithms different math, different authors, different attack surfaces.<br>
If an attacker somehow breaks one, the other catches it. No other distro does this.
</p>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:1.5rem;max-width:800px;margin:0 auto 1.5rem;">
<h3 style="color:var(--accent2);margin-bottom:1rem;font-size:1rem;">SHA-256 <span style="color:var(--dim);font-weight:400;font-size:0.85rem;">(NIST Standard)</span></h3>
<div style="background:#0a0a0f;border-radius:8px;padding:0.8rem 1rem;font-family:monospace;font-size:0.8rem;word-break:break-all;color:var(--gold);margin-bottom:0.5rem;">
7d49ef3cfb957cb9854bd3f451ef99ec8255afd68069a89ed0cf5a847d5d79bf
</div>
<div style="font-size:0.8rem;color:var(--dim);">
<code style="color:var(--text);background:#1e1e2e;padding:2px 6px;border-radius:4px;">sha256sum alfred-linux-4.0-rc8-amd64-20260407.iso</code>
</div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:1.5rem;max-width:800px;margin:0 auto 1.5rem;">
<h3 style="color:var(--accent);margin-bottom:1rem;font-size:1rem;">BLAKE3 <span style="color:var(--dim);font-weight:400;font-size:0.85rem;">(Fastest &amp; most secure hash on the planet)</span></h3>
<div style="background:#0a0a0f;border-radius:8px;padding:0.8rem 1rem;font-family:monospace;font-size:0.8rem;word-break:break-all;color:var(--accent2);margin-bottom:0.5rem;">
e021d2024599aa918972d9e6b9fd9c1d97d226ac69da035913fd7a462dbef47d
</div>
<div style="font-size:0.8rem;color:var(--dim);">
<code style="color:var(--text);background:#1e1e2e;padding:2px 6px;border-radius:4px;">b3sum alfred-linux-4.0-rc8-amd64-20260407.iso</code>
&nbsp;·&nbsp; Install: <code style="color:var(--text);background:#1e1e2e;padding:2px 6px;border-radius:4px;">pip install blake3</code> or <code style="color:var(--text);background:#1e1e2e;padding:2px 6px;border-radius:4px;">cargo install b3sum</code>
</div>
</div>
<p style="color:var(--dim);text-align:center;font-size:0.85rem;margin-top:1rem;">
Both hashes must match. If either one doesn't <strong style="color:var(--danger);">do not install</strong>. Re-download via P2P.
</p>
</section>
<!-- ── How It Works ────────────────────────────── -->
<section class="how-it-works">
<h2>How Peer-to-Peer Download Works</h2>
<div class="steps">
<div class="step">
<div class="step-num">1</div>
<div>
<h3>Click "Start P2P Download"</h3>
<p>Your browser connects to the Alfred Linux swarm using WebTorrent a BitTorrent client that runs natively in your browser. No plugins, no installs.</p>
</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div>
<h3>Download from everyone at once</h3>
<p>Instead of one server, you download pieces from every peer in the swarm simultaneously. More people = faster download for everyone.</p>
</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div>
<h3>You become a seeder</h3>
<p>While downloading, you're already sharing completed pieces with others. When done, you keep sharing as long as the page stays open.</p>
</div>
</div>
<div class="step">
<div class="step-num">4</div>
<div>
<h3>The swarm grows stronger</h3>
<p>Every seeder makes the next download faster. You're not just getting an OS — you're powering a movement. The longer you seed, the more people you help.</p>
</div>
</div>
</div>
</section>
<!-- ── Footer ──────────────────────────────────── -->
<footer>
<p>Alfred Linux &copy; <?= date('Y') ?> · <a href="/">alfredlinux.com</a> · <a href="/forge/">GoForge</a> · Powered by WebTorrent + the Community</p>
</footer>
<!-- ── WebTorrent Browser Client ───────────────── -->
<script src="/assets/js/webtorrent.min.js"></script>
<script>
(function() {
'use strict';
// ── Config ────────────────────────────────────
const ISO_NAME = <?= json_encode($isoName) ?>;
const DIRECT_URL = ''; // Torrent-only distribution
const TORRENT_URL = <?= json_encode($torrentURL) ?>;
const MAGNET_URI = <?= json_encode($magnetURI) ?>;
let client = null;
let torrent = null;
let seedStart = null;
let blobURL = null;
let seedTimer = null;
// ── UI Elements ───────────────────────────────
const $start = document.getElementById('start-section');
const $progress = document.getElementById('progress-section');
const $seed = document.getElementById('seed-section');
const $error = document.getElementById('error-box');
// ── Format helpers ────────────────────────────
function fmtBytes(b) {
if (b < 1024) return b + ' B';
if (b < 1048576) return (b / 1024).toFixed(1) + ' KB';
if (b < 1073741824) return (b / 1048576).toFixed(1) + ' MB';
return (b / 1073741824).toFixed(2) + ' GB';
}
function fmtSpeed(bps) {
if (bps < 1024) return bps + ' B/s';
if (bps < 1048576) return (bps / 1024).toFixed(0) + ' KB/s';
return (bps / 1048576).toFixed(1) + ' MB/s';
}
function fmtTime(secs) {
if (!secs || secs === Infinity) return '—';
const h = Math.floor(secs / 3600);
const m = Math.floor((secs % 3600) / 60);
const s = Math.floor(secs % 60);
return (h > 0 ? h + 'h ' : '') + m + 'm ' + s + 's';
}
function fmtTimer(secs) {
const h = String(Math.floor(secs / 3600)).padStart(2, '0');
const m = String(Math.floor((secs % 3600) / 60)).padStart(2, '0');
const s = String(Math.floor(secs % 60)).padStart(2, '0');
return h + ':' + m + ':' + s;
}
// ── Start Download ────────────────────────────
window.startDownload = function() {
if (!window.WebTorrent) {
showError('WebTorrent library failed to load. Please <a href="' + TORRENT_URL + '">download the .torrent file</a> and use a desktop torrent client instead.');
return;
}
try {
client = new WebTorrent();
} catch (e) {
showError('Could not initialize WebTorrent: ' + e.message + '. <a href="' + TORRENT_URL + '">Download .torrent file</a> instead.');
return;
}
client.on('error', function(err) {
console.error('WebTorrent error:', err);
showError('Torrent error: ' + err.message + '. <a href="' + TORRENT_URL + '">Download .torrent file</a> and use a desktop torrent client instead.');
});
$start.style.display = 'none';
$progress.style.display = 'block';
// Use magnet URI directly — most reliable method for browser WebTorrent
console.log('[Alfred] Adding torrent via magnet URI');
addTorrentFromMagnet(MAGNET_URI);
};
function addTorrentFromMagnet(magnetURI) {
client.add(magnetURI, {
announce: [
'wss://tracker.openwebtorrent.com',
]
}, function(t) {
torrent = t;
console.log('Torrent added:', t.infoHash, '— Files:', t.files.length);
// Update progress periodically
var progressInterval = setInterval(function() {
var pct = Math.round(torrent.progress * 100);
document.getElementById('progress-bar').style.width = pct + '%';
document.getElementById('progress-pct').textContent = pct + '%';
document.getElementById('stat-downloaded').textContent = fmtBytes(torrent.downloaded);
document.getElementById('stat-speed').textContent = fmtSpeed(torrent.downloadSpeed);
document.getElementById('stat-peers').textContent = torrent.numPeers;
document.getElementById('stat-eta').textContent = fmtTime(torrent.timeRemaining / 1000);
document.getElementById('stat-uploaded').textContent = fmtBytes(torrent.uploaded);
// Update swarm counter
document.getElementById('swarm-count').textContent = torrent.numPeers;
}, 500);
torrent.on('done', function() {
clearInterval(progressInterval);
showSeedMode();
});
});
};
// ── Seed Mode ─────────────────────────────────
function showSeedMode() {
$progress.style.display = 'none';
$seed.style.display = 'block';
seedStart = Date.now();
// Save button — use File System Access API for large files, fall back to direct HTTP
var saveBtn = document.getElementById('save-btn');
saveBtn.onclick = async function() {
// Try modern File System Access API first (Chrome/Edge 86+)
if (window.showSaveFilePicker) {
try {
var handle = await window.showSaveFilePicker({
suggestedName: ISO_NAME,
types: [{ description: 'ISO Image', accept: { 'application/octet-stream': ['.iso'] } }]
});
var writable = await handle.createWritable();
var file = torrent.files[0];
var stream = file.createReadStream();
saveBtn.textContent = 'Saving...';
saveBtn.disabled = true;
stream.on('data', function(chunk) { writable.write(chunk); });
stream.on('end', function() {
writable.close();
saveBtn.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18"><path d="M20 6L9 17l-5-5"/></svg> Saved!';
});
stream.on('error', function(e) {
console.error('Stream error:', e);
writable.close();
// Fall back to direct download
triggerDirectDownload();
});
return;
} catch (e) {
if (e.name === 'AbortError') return; // user cancelled
console.warn('File System Access failed:', e);
}
}
// Fallback: direct HTTP download (file already came via P2P, this just saves it)
triggerDirectDownload();
};
function triggerDirectDownload() {
// Save from WebTorrent blob — ISO is not served via HTTP
if (!torrent || !torrent.files || !torrent.files[0]) {
showError('No downloaded file available. Please re-download via P2P.');
return;
}
torrent.files[0].getBlob(function(err, blob) {
if (err) {
showError('Could not create file: ' + err.message);
return;
}
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = ISO_NAME;
a.click();
setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
});
}
// Show the Flash to USB guide
var flashGuide = document.getElementById('flash-guide');
if (flashGuide) flashGuide.classList.add('visible');
// Seed stats updater
seedTimer = setInterval(function() {
var elapsed = Math.floor((Date.now() - seedStart) / 1000);
document.getElementById('seed-timer').textContent = fmtTimer(elapsed);
document.getElementById('seed-uploaded').textContent = fmtBytes(torrent.uploaded);
document.getElementById('seed-speed').textContent = fmtSpeed(torrent.uploadSpeed);
document.getElementById('seed-peers').textContent = torrent.numPeers;
document.getElementById('seed-ratio').textContent = torrent.ratio.toFixed(2);
document.getElementById('swarm-count').textContent = torrent.numPeers;
}, 1000);
}
// ── Share ─────────────────────────────────────
window.shareTwitter = function() {
var text = encodeURIComponent(
"I just downloaded Alfred Linux via peer-to-peer — directly in my browser! 🐧⚡\n\n" +
"No torrent client needed. The more people who download, the faster it gets for everyone.\n\n" +
"Join the swarm: https://alfredlinux.com/download\n\n#AlfredLinux #OpenSource #P2P"
);
window.open('https://x.com/intent/tweet?text=' + text, '_blank', 'noopener,noreferrer');
};
window.shareLink = function() {
navigator.clipboard.writeText('https://alfredlinux.com/download').then(function() {
var btn = document.querySelector('.share-btn:last-child');
btn.textContent = '✅ Copied!';
setTimeout(function() { btn.textContent = '🔗 Copy Link'; }, 2000);
});
};
// ── Error handling ────────────────────────────
function showError(msg) {
$error.style.display = 'block';
$error.innerHTML = msg;
}
// ── Swarm Visualization ───────────────────────
(function initSwarmVis() {
var canvas = document.getElementById('swarm-canvas');
if (!canvas) return;
var ctx = canvas.getContext('2d');
var particles = [];
function resize() {
canvas.width = canvas.parentElement.clientWidth;
canvas.height = 200;
}
resize();
window.addEventListener('resize', resize);
// Create initial particles
for (var i = 0; i < 30; i++) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 0.8,
vy: (Math.random() - 0.5) * 0.8,
r: 2 + Math.random() * 3,
color: Math.random() > 0.5 ? '#6c5ce7' : '#00cec9',
});
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw connections
for (var i = 0; i < particles.length; i++) {
for (var j = i + 1; j < particles.length; j++) {
var dx = particles[i].x - particles[j].x;
var dy = particles[i].y - particles[j].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 120) {
ctx.beginPath();
ctx.strokeStyle = 'rgba(108,92,231,' + (1 - dist / 120) * 0.2 + ')';
ctx.lineWidth = 0.5;
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[j].x, particles[j].y);
ctx.stroke();
}
}
}
// Draw particles
for (var k = 0; k < particles.length; k++) {
var p = particles[k];
p.x += p.vx;
p.y += p.vy;
if (p.x < 0 || p.x > canvas.width) p.vx *= -1;
if (p.y < 0 || p.y > canvas.height) p.vy *= -1;
ctx.beginPath();
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
ctx.fillStyle = p.color;
ctx.fill();
ctx.beginPath();
ctx.arc(p.x, p.y, p.r + 4, 0, Math.PI * 2);
ctx.fillStyle = p.color.replace(')', ',0.15)').replace('rgb', 'rgba');
ctx.fill();
}
requestAnimationFrame(draw);
}
draw();
// Add particles when peers connect
setInterval(function() {
var count = torrent ? torrent.numPeers : 0;
while (particles.length < Math.min(count + 10, 80)) {
particles.push({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 0.8,
vy: (Math.random() - 0.5) * 0.8,
r: 2 + Math.random() * 3,
color: Math.random() > 0.5 ? '#6c5ce7' : '#00cec9',
});
}
}, 3000);
})();
// ── Flash to USB tab switching ────────────────
window.showFlashTab = function(tab) {
document.querySelectorAll('.flash-tab').forEach(function(t) { t.classList.remove('active'); });
document.querySelectorAll('.flash-panel').forEach(function(p) { p.classList.remove('active'); });
event.target.classList.add('active');
var panel = document.getElementById('flash-' + tab);
if (panel) panel.classList.add('active');
};
window.copyCmd = function(btn) {
var code = btn.parentElement.querySelector('code').textContent;
navigator.clipboard.writeText(code).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
// Auto-select the right tab based on OS
(function detectOS() {
var ua = navigator.userAgent;
var tab = 'etcher'; // default
if (/Win/.test(ua)) tab = 'windows';
else if (/Mac/.test(ua)) tab = 'mac';
else if (/Linux/.test(ua)) tab = 'linux';
document.querySelectorAll('.flash-tab').forEach(function(t) { t.classList.remove('active'); });
document.querySelectorAll('.flash-panel').forEach(function(p) { p.classList.remove('active'); });
var tabs = document.querySelectorAll('.flash-tab');
tabs.forEach(function(t) { if (t.textContent.toLowerCase().indexOf(tab === 'windows' ? 'windows' : tab === 'mac' ? 'mac' : tab === 'linux' ? 'linux' : 'etcher') !== -1) t.classList.add('active'); });
var panel = document.getElementById('flash-' + tab);
if (panel) panel.classList.add('active');
})();
// ── Warn before leaving while seeding ─────────
window.addEventListener('beforeunload', function(e) {
if (torrent && torrent.done) {
e.preventDefault();
e.returnValue = 'You\'re currently seeding Alfred Linux for the community. Are you sure you want to leave?';
}
});
})();
</script>
<footer style="text-align:center;padding:1.5rem;color:#94a3b8;font-size:.85rem;border-top:1px solid rgba(255,255,255,0.06);">
&copy; <?= date('Y') ?> <a href="https://gositeme.com" style="color:#6366f1;text-decoration:none;">GoSiteMe Inc.</a> &mdash; Alfred Linux &middot; Open Source (AGPL-3.0)
</footer>
</body>
</html>