summaryrefslogtreecommitdiff
path: root/web/share.html
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-30 12:45:18 +0300
committerPaul Buetow <paul@buetow.org>2026-04-30 12:45:18 +0300
commit54bc9013aa0463962a1cfd67fa278de3d401d85a (patch)
tree526c719285a6153fdc82f8a7feb7b4ef98c1ce78 /web/share.html
parent38e318e71d50e4340ddbf1ae63b3d85e958b4644 (diff)
ja: implement public share landing page and improve error mapping
- Add web/share.html with a minimal HTML5 video player, theme variables, centered layout, play overlay, and Back to Home link. - Update handleSharePage to return HTML for browser Accept headers (text/html or empty) and JSON for application/json. Return 410 Gone for expired shares. - Update handleShareStream to map service errors to distinct HTTP codes: ErrShareExpired -> 410, ErrShareNotFound/ErrMediaNotFound -> 404. - Improve ValidateShareToken and StreamSharedMedia to return sentinel errors (ErrShareNotFound, ErrShareExpired, ErrMediaNotFound) instead of generic string errors. - Update and add tests for share page HTML/JSON negotiation and share stream 404/410 responses.
Diffstat (limited to 'web/share.html')
-rw-r--r--web/share.html105
1 files changed, 105 insertions, 0 deletions
diff --git a/web/share.html b/web/share.html
new file mode 100644
index 0000000..065e839
--- /dev/null
+++ b/web/share.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Shared Media</title>
+<link rel="stylesheet" href="/css/theme.css">
+<style>
+ body {
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ min-height: 100vh;
+ background: var(--bg-body);
+ color: var(--text-primary);
+ font-family: var(--font-sans);
+ padding: 1rem;
+ box-sizing: border-box;
+ }
+ .container {
+ width: 100%;
+ max-width: 720px;
+ text-align: center;
+ }
+ h1 {
+ margin: 0 0 1rem;
+ font-size: 1.25rem;
+ color: var(--text-primary);
+ }
+ .player-wrapper {
+ position: relative;
+ background: var(--player-bg);
+ border-radius: var(--radius-md);
+ overflow: hidden;
+ box-shadow: var(--shadow-md);
+ }
+ video, audio {
+ width: 100%;
+ display: block;
+ }
+ .play-overlay {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--bg-overlay);
+ cursor: pointer;
+ transition: opacity var(--transition-base);
+ }
+ .play-overlay.hidden {
+ opacity: 0;
+ pointer-events: none;
+ }
+ .play-icon {
+ font-size: 3rem;
+ color: var(--text-primary);
+ background: var(--accent-soft);
+ border-radius: 50%;
+ width: 4rem;
+ height: 4rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1;
+ }
+ .back-link {
+ margin-top: 1.5rem;
+ color: var(--accent);
+ text-decoration: none;
+ font-size: 0.9rem;
+ }
+ .back-link:hover {
+ color: var(--accent-hover);
+ }
+</style>
+</head>
+<body>
+<div class="container">
+ <h1>Shared Media</h1>
+ <div class="player-wrapper">
+ <video id="player" playsinline preload="metadata" src="./stream"></video>
+ <div id="overlay" class="play-overlay" role="button" aria-label="Play">
+ <div class="play-icon">▶</div>
+ </div>
+ </div>
+ <a class="back-link" href="/">Back to Home</a>
+</div>
+<script>
+ const player = document.getElementById('player');
+ const overlay = document.getElementById('overlay');
+ overlay.addEventListener('click', () => {
+ player.play();
+ });
+ player.addEventListener('play', () => {
+ overlay.classList.add('hidden');
+ });
+ player.addEventListener('pause', () => {
+ overlay.classList.remove('hidden');
+ });
+</script>
+</body>
+</html>