comparison mrjunejune/test/snapshots/tools_hls_player.snapshot @ 242:543df0fe7168

[tools] Add full HLS player support
author MrJuneJune <me@mrjunejune.com>
date Mon, 03 Aug 2026 13:14:41 -0700
parents
children 30c2196d03d4
comparison
equal deleted inserted replaced
241:9c2eec61a152 242:543df0fe7168
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta name="theme-color" content="#544e43">
7 <link rel="icon" type="image/svg+xml" href="/public/epi_all_colors.svg">
8 <link rel="manifest" href="/public/manifest.json">
9 <link rel="apple-touch-icon" href="/public/epi_all_colors.svg">
10
11 <link rel="preload" href="/public/fonts/Roboto-Regular.ttf" as="font" crossorigin>
12 <link rel="preload" href="/public/fonts/Roboto-Thin.ttf"as="font" crossorigin>
13
14 <!-- <link rel="preload" href="/public/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin> -->
15 <!-- <link rel="preload" href="/public/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin> -->
16
17 <!-- <link rel="preload" href="/public/fonts/more-sugar.extras.otf" as="font" type="font/otf" crossorigin> -->
18 <link rel="preload" href="/public/fonts/more-sugar.regular.otf" as="font" type="font/otf" crossorigin>
19 <link rel="preload" href="/public/fonts/more-sugar.thin.otf" as="font" type="font/otf" crossorigin>
20 <link rel="preload" href="/public/epi_all_colors.svg" as="image">
21
22 <link rel="preload" href="/base.css" as="style" />
23 <link rel="stylesheet" href="/base.css" />
24
25 <script src="/public/pwa-register.js" defer></script>
26
27
28 <title>HLS Player - MrJuneJune</title>
29 <link rel="stylesheet" href="/tools/hls_player/index.css" />
30 <script src="/public/hls.min.js" defer></script>
31 <script src="/tools/hls_player/hls-player.js" defer></script>
32 </head>
33 <body>
34 <style>
35 :root {
36 --header-background: var(--white);
37 --header-color: rgb(var(--black));
38 --link-hover-accent: var(--awesome);
39 }
40
41 /* Fixed icon in top left corner */
42 #themeToggle {
43 position: fixed;
44 top: 20px;
45 left: 20px;
46 background: var(--header-background);
47 display: flex;
48 align-items: center;
49 border-radius: 50%;
50 cursor: pointer;
51 z-index: 1000;
52 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
53 transition: transform 0.2s ease;
54 }
55
56 #themeToggle:hover {
57 transform: scale(1.05);
58 }
59
60 /* Professional header */
61 header {
62 margin: auto;
63 padding: 1.5em 1em;
64 font-family: "More", sans-serif;
65 box-shadow: 0 2px 8px rgba(var(--black), 5%);
66 width: 720px;
67 max-width: calc(100% - 2em);
68 text-align: center;
69 }
70
71 header h1 {
72 margin: 0;
73 font-size: 1.8em;
74 font-weight: 700;
75 letter-spacing: -0.5px;
76 }
77
78 header h1 a {
79 text-decoration: none;
80 color: var(--header-color);
81 }
82
83 header h1 a::before {
84 display: none;
85 }
86
87 /* Mobile responsiveness */
88 @media (max-width: 720px) {
89 #themeToggle {
90 top: 15px;
91 left: 15px;
92 }
93
94 header {
95 padding: 1em;
96 }
97
98 header h1 {
99 font-size: 1.5em;
100 }
101 }
102
103 @media (max-width: 480px) {
104 #themeToggle {
105 top: 10px;
106 left: 10px;
107 }
108
109 #themeToggle img {
110 height: 40px;
111 width: 40px;
112 }
113
114 header h1 {
115 font-size: 1.3em;
116 }
117 }
118
119 #logo {
120 width: 300px;
121 }
122
123 /* 1. DEFINE THE DEFAULTS (Light Mode) */
124 :root {
125 --logo-invert: invert(0);
126 --epi-grayscale: grayscale(0) brightness(1);
127 }
128
129 /* 2. MANUAL DARK OVERRIDE */
130 html.dark {
131 --logo-invert: invert(1);
132 --epi-grayscale: grayscale(1);
133 }
134
135 /* 3. MANUAL LIGHT OVERRIDE */
136 html.light-mode {
137 --logo-invert: invert(0);
138 --epi-grayscale: brightness(2.9) grayscale(1);
139 }
140
141 /* 4. SYSTEM PREFERENCE */
142 @media (prefers-color-scheme: dark) {
143 :root:not(.light-mode) {
144 --logo-invert: invert(1);
145 }
146 }
147
148 /* 5. APPLY TO ELEMENTS */
149 #logo {
150 -webkit-filter: var(--logo-invert);
151 filter: var(--logo-invert);
152 transition: filter 0.3s ease;
153 }
154
155 .epi-logo {
156 -webkit-filter: var(--epi-grayscale);
157 filter: var(--epi-grayscale);
158 transition: filter 0.3s ease;
159 }
160 </style>
161
162 <div id="themeToggle">
163 <img id="epiChan" class="epi-logo" aria-label="Toggle dark mode" src="/public/epi_all_colors.svg" height="50" width="50">
164 </div>
165
166 <header>
167 <h1><a href="/">MrJuneJune</a></h1>
168 </header>
169 <script src="/index.js"></script>
170
171
172 <main>
173 <h1>Online HLS Player</h1>
174 <p>Load an HLS playlist from a URL, or try the sample stream bundled with this site.</p>
175
176 <form id="hlsForm" class="hls-form">
177 <label for="hlsUrl">Playlist URL</label>
178 <div class="hls-url-row">
179 <input
180 id="hlsUrl"
181 name="url"
182 type="text"
183 inputmode="url"
184 value="/public/hls-sample/h264-ts-stream.m3u8"
185 placeholder="https://example.com/stream.m3u8"
186 required
187 />
188 <button type="submit">Load</button>
189 <button id="sampleButton" type="button">Sample</button>
190 </div>
191 </form>
192
193 <fieldset class="hls-local-picker">
194 <legend>Local HLS</legend>
195 <p>Select the playlist together with every init and segment file it references.</p>
196 <div class="hls-local-actions">
197 <label class="hls-file-button">
198 Choose HLS files
199 <input
200 id="hlsFiles"
201 type="file"
202 accept=".m3u8,.m4s,.mp4,.ts,.aac,.vtt,.key,application/vnd.apple.mpegurl"
203 multiple
204 />
205 </label>
206 <label class="hls-file-button">
207 Choose HLS folder
208 <input
209 id="hlsFolder"
210 type="file"
211 webkitdirectory
212 multiple
213 />
214 </label>
215 </div>
216 </fieldset>
217
218 <div class="hls-player-shell">
219 <video id="hlsVideo" controls playsinline preload="metadata"></video>
220 <p id="hlsStatus" class="hls-status" role="status" aria-live="polite">Ready to load a playlist.</p>
221 </div>
222
223 <dl id="hlsDetails" class="hls-details" hidden>
224 <div>
225 <dt>Playback</dt>
226 <dd data-detail="mode">-</dd>
227 </div>
228 <div>
229 <dt>Segments</dt>
230 <dd data-detail="segments">-</dd>
231 </div>
232 <div>
233 <dt>Duration</dt>
234 <dd data-detail="duration">-</dd>
235 </div>
236 <div>
237 <dt>Codec</dt>
238 <dd data-detail="codecs">-</dd>
239 </div>
240 </dl>
241
242 <section class="hls-notes">
243 <h2>Notes</h2>
244 <ul>
245 <li>Remote playlists must allow cross-origin requests.</li>
246 <li>Local loading stays in your browser; selected files are not uploaded.</li>
247 <li>Chrome, Edge, and Firefox support MPEG-TS, fragmented MP4, live, and adaptive HLS through hls.js.</li>
248 <li>Safari uses native HLS playback when available.</li>
249 </ul>
250 </section>
251 </main>
252 <div style="display: flex; align-items: center; justify-content: center; margin: 30px 0px;">
253 <small>&copy; 2026 June Park</small>
254 </div>
255
256 </body>
257 </html>