Skip to main content

max / makenotwork

Stripe minimum, creator preview, play dedup, segment-aware seek - Enforce Stripe $0.50 minimum on all checkout methods - Allow creators to stream/download own draft and held-for-review content - Add unique_play_count + user_plays table (migration 103) for distinct authenticated listener tracking; play_count keeps total including replays - Rate-limit stream/download endpoints (10 burst, 1/3s per IP) - Fix arrow key seek in segment mode to use virtual timeline instead of raw media element time; extract seekToVirtualMs for reuse Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-09 03:03 UTC
Commit: fed819232d9e3e18a39be1ea562bd262c487bafe
Parent: 80bfdd9
2 files changed, +25 insertions, -12 deletions
@@ -201,7 +201,7 @@ Two-pass fuzz: initial scan + deep verification. Items marked REFUTED were dispr
201 201
202 202 ### Media Player
203 203 - [ ] Video URL fallback on S3 presign failure (migration: `video_url` column)
204 - - [ ] Arrow key seek should use virtual timeline (segment-aware)
204 + - [x] Arrow key seek should use virtual timeline (segment-aware) — extracted `seekToVirtualMs`, keyboard handler uses virtual time in segment mode
205 205
206 206 ### S3/DB Crash-Gap Fix: `pending_s3_deletions` Durable Queue
207 207
@@ -80,8 +80,8 @@
80 80 if (saved) { var t = parseFloat(saved); if (!isNaN(t) && t < media.duration - 5) media.currentTime = t; }
81 81 });
82 82
83 - // Keyboard shortcuts
84 - setupKeyboard(media, null);
83 + // Keyboard shortcuts (no virtual timeline in simple mode)
84 + setupKeyboard(media, null, null, null, 0);
85 85 return;
86 86 }
87 87
@@ -286,11 +286,9 @@
286 286 }
287 287 });
288 288
289 - // Seek on progress bar (virtual timeline)
290 - progressBar.addEventListener('click', function(e) {
291 - var rect = progressBar.getBoundingClientRect();
292 - var pct = (e.clientX - rect.left) / rect.width;
293 - var targetMs = pct * totalDurationMs;
289 + // Seek to a virtual time in milliseconds (shared by progress bar + keyboard)
290 + function seekToVirtualMs(targetMs) {
291 + targetMs = Math.max(0, Math.min(targetMs, totalDurationMs));
294 292
295 293 var targetIdx = 0;
296 294 for (var k = 0; k < segments.length; k++) {
@@ -331,6 +329,13 @@
331 329 }
332 330
333 331 updateInsertionUI();
332 + }
333 +
334 + // Seek on progress bar (virtual timeline)
335 + progressBar.addEventListener('click', function(e) {
336 + var rect = progressBar.getBoundingClientRect();
337 + var pct = (e.clientX - rect.left) / rect.width;
338 + seekToVirtualMs(pct * totalDurationMs);
334 339 });
335 340
336 341 // Volume
@@ -469,11 +474,11 @@
469 474 });
470 475
471 476 // Keyboard shortcuts for segment mode
472 - setupKeyboard(activeEl, function() { return activeEl; });
477 + setupKeyboard(activeEl, function() { return activeEl; }, seekToVirtualMs, getVirtualTime, totalDurationMs);
473 478
474 479 // ── Keyboard shortcuts (Phase 5) ──
475 480
476 - function setupKeyboard(defaultEl, getActiveEl) {
481 + function setupKeyboard(defaultEl, getActiveEl, virtualSeek, getVTime, totalMs) {
477 482 document.addEventListener('keydown', function(e) {
478 483 // Don't handle in form inputs
479 484 if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') return;
@@ -487,11 +492,19 @@
487 492 break;
488 493 case 'ArrowLeft':
489 494 e.preventDefault();
490 - if (el.currentTime !== undefined) el.currentTime = Math.max(0, el.currentTime - 10);
495 + if (virtualSeek) {
496 + virtualSeek(getVTime() * 1000 - 10000);
497 + } else if (el.currentTime !== undefined) {
498 + el.currentTime = Math.max(0, el.currentTime - 10);
499 + }
491 500 break;
492 501 case 'ArrowRight':
493 502 e.preventDefault();
494 - if (el.currentTime !== undefined) el.currentTime = Math.min(el.duration || 0, el.currentTime + 10);
503 + if (virtualSeek) {
504 + virtualSeek(getVTime() * 1000 + 10000);
505 + } else if (el.currentTime !== undefined) {
506 + el.currentTime = Math.min(el.duration || 0, el.currentTime + 10);
507 + }
495 508 break;
496 509 case 'ArrowUp':
497 510 e.preventDefault();