Files
oib 402e920bc6 Fix double audio playback and add UID handling for personal stream
- Fixed double playback issue on stream page by properly scoping event delegation in streams-ui.js
- Added init-personal-stream.js to handle UID for personal stream playback
- Improved error handling and logging for audio playback
- Added proper event propagation control to prevent duplicate event handling
2025-07-18 16:51:39 +02:00

222 lines
9.0 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/static/style.css" media="all" />
<link rel="stylesheet" href="/static/desktop.css" media="(min-width: 960px)">
<link rel="stylesheet" href="/static/mobile.css" media="(max-width: 959px)">
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎙️</text></svg>">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="dicta2stream is a minimalist voice streaming platform for looping your spoken audio anonymously." />
<title>dicta2stream</title>
<!-- Section visibility and navigation styles -->
<link rel="stylesheet" href="/static/css/section.css" media="all" />
<style>
/* Hide mobile menu by default on larger screens */
@media (min-width: 960px) {
#mobile-menu { display: none !important; }
#burger-label { display: none !important; }
}
</style>
<link rel="modulepreload" href="/static/sound.js" />
<script src="/static/streams-ui.js" type="module"></script>
<script src="/static/app.js" type="module"></script>
</head>
<body>
<header>
<h1>dicta2stream 🎙️</h1>
<p>Your voice. Your loop. One drop away.</p>
</header>
<main>
<!-- Guest Dashboard -->
<nav id="guest-dashboard" class="dashboard-nav guest-only">
<a href="#welcome-page" id="guest-welcome">Welcome</a>
<a href="#stream-page" id="guest-streams">Streams</a>
<a href="#account" id="guest-login">Account</a>
</nav>
<!-- User Dashboard -->
<nav id="user-dashboard" class="dashboard-nav auth-only">
<a href="#welcome-page" id="user-welcome">Welcome</a>
<a href="#stream-page" id="user-streams">Streams</a>
<a href="#me-page" id="show-me">Your Stream</a>
</nav>
<section id="me-page" class="auth-only">
<div>
<h2>Your Stream</h2>
</div>
<article>
<p>This is your personal stream. Only you can upload to it.</p>
<audio id="me-audio"></audio>
<div class="audio-controls">
<button class="play-pause-btn" type="button" aria-label="Play" data-uid="">▶️</button>
</div>
</article>
<section id="user-upload-area" class="auth-only">
<p>Drag & drop your audio file here<br>or click to browse</p>
<input type="file" id="fileInputUser" accept="audio/*" hidden />
</section>
<article id="log-out" class="auth-only article--bordered logout-section">
<button id="logout-button" class="button">🚪 Log Out</button>
</article>
<section id="quota-meter" class="auth-only">
<p class="quota-meter">Quota: <progress id="quota-bar" value="0" max="100"></progress> <span id="quota-text">0 MB</span></p>
<h4>Uploaded Files</h4>
<ul id="file-list" class="file-list">
<li>Loading files...</li>
</ul>
</section>
</section>
<div id="spinner" class="spinner"></div>
<!-- Burger menu and legacy links section removed for clarity -->
<section id="terms-page" class="always-visible">
<h2>Terms of Service</h2>
<article class="article--bordered">
<p>By accessing or using dicta2stream.net (the "Service"), you agree to be bound by these Terms of Service ("Terms"). If you do not agree, do not use the Service.</p>
<ul>
<li>You must be at least 18 years old to register.</li>
<li>Each account must be unique and used by only one person.</li>
<li>One account per device/IP per 24 hours.</li>
<li>If hate speech, illegal, or harmful content is detected, the account and all associated data will be deleted.</li>
<li>The associated email address will be banned from recreating an account.</li>
<li>Uploads are limited to 100 MB and must be voice only.</li>
<li>Music/singing will be rejected.</li>
</ul>
</article>
</section>
<section id="privacy-page" class="always-visible">
<div>
<h2>Privacy Policy</h2>
</div>
<article class="article--bordered">
<ul>
<li><strong>Users</strong>: Session uses both cookies and localStorage to store UID and authentication state.</li>
<li><strong>Guests</strong>: No cookies are set. No persistent identifiers are stored.</li>
<li>We log IP + UID only for abuse protection and quota enforcement.</li>
<li>Uploads are scanned via Whisper+Ollama but not stored as transcripts.</li>
<li>Data is never sold.</li>
</ul>
</article>
<!-- This section will be shown only to authenticated users -->
<div class="auth-only">
<section id="account-deletion" class="article--bordered">
<h3>Account Deletion</h3>
<p>You can delete your account and all associated data at any time. This action is irreversible and will permanently remove:</p>
<ul>
<li>Your account information</li>
<li>All uploaded audio files</li>
</ul>
<div class="centered-container">
<button id="delete-account-from-privacy" class="button">
🗑️ Delete My Account
</button>
</div>
</section>
</div>
<!-- Guest login message removed as per user request -->
</section>
<section id="imprint-page" class="always-visible">
<h2>Imprint</h2>
<article class="article--bordered">
<p><strong>Andreas Michael Fleckl</strong></p>
<p>Johnstrassse 7/6<br>1140 Vienna<br>Austria / Europe</p>
</article>
</section>
<section id="welcome-page" class="always-visible">
<h2>Welcome</h2>
<article class="article--bordered">
<p>dicta2stream is a minimalist voice streaming platform for your spoken audio anonymously under a nickname in a loop. <span class="text-muted">(Opus | Mono | 48kHz | 60kbps)</span><br><br>
<strong>What you can do here:</strong></p>
<ul>
<li>🎧 Listen to public voice streams from others, instantly</li>
<li>🎙️ Upload your own audio and share your voice with the world</li>
<li>🕵️ No sign-up required for listening</li>
<li>🔒 Optional registration for uploading and managing your own stream</li>
</ul>
<div class="email-section">
<a href="mailto:Andreas.Fleckl@dicta2stream.net" class="button">
Andreas.Fleckl@dicta2stream.net
</a>
</div>
</article>
</section>
<section id="stream-page" class="always-visible">
<h2>Public Streams</h2>
<!-- The list below is dynamically populated by streams-ui.js; shows 'Loading...' while fetching -->
<ul id="stream-list"><li>Loading...</li></ul>
</section>
<section id="register-page" class="guest-only">
<h2>Account</h2>
<article class="article--wide">
<form id="register-form">
<p><label>Email<br><input type="email" name="email" required /></label></p>
<p><label>Username<br><input type="text" name="user" required /></label></p>
<p class="bot-trap">
<label>Leave this empty:<br>
<input type="text" name="bot_trap" autocomplete="off" />
</label>
</p>
<p><button type="submit">Login / Create Account</button></p>
</form>
<p class="form-note">You'll receive a magic login link via email. No password required.</p>
<p class="form-note session-note">Your session expires after 1 hour. Shareable links redirect to homepage.</p>
</article>
</section>
</main>
<footer>
<p class="footer-links">
<a href="#" id="footer-terms" data-target="terms-page">Terms</a> |
<a href="#" id="footer-privacy" data-target="privacy-page">Privacy</a> |
<a href="#" id="footer-imprint" data-target="imprint-page">Imprint</a>
</p>
</footer>
<script type="module" src="/static/dashboard.js"></script>
<script type="module" src="/static/app.js"></script>
<!-- Load public streams UI logic -->
<script type="module" src="/static/streams-ui.js"></script>
<!-- Load upload functionality -->
<script type="module" src="/static/upload.js"></script>
<script type="module">
import "/static/nav.js";
window.addEventListener("pageshow", () => {
const dz = document.querySelector("#user-upload-area");
if (dz) dz.classList.remove("uploading");
const spinner = document.querySelector("#spinner");
if (spinner) spinner.style.display = "none";
});
</script>
<script type="module">
import { initMagicLogin } from '/static/magic-login.js';
const params = new URLSearchParams(window.location.search);
if (params.has('token')) {
if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', initMagicLogin);
} else {
initMagicLogin();
}
}
</script>
<script type="module" src="/static/init-personal-stream.js"></script>
</body>
</html>