Commit 72be29144b6f4ba78cfae8920d4fb1dca76e4b17

Authored by yibo
1 parent e303b2e4

Default the live player to sound-on instead of muted

Drops the muted attribute and tries an unmuted autoplay first; if the browser
blocks unmuted autoplay (no prior user gesture on the page), falls back to
muted playback and syncs the mute button label to match. Once a viewer
unmutes once, later clip switches keep playing with sound.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0144MiJ2cLjMd9jWaeEpVfUJ
Showing 2 changed files with 64 additions and 53 deletions
library.json
... ... @@ -199,7 +199,7 @@
199 199 "likes": 0,
200 200 "createdAt": 1788192913244,
201 201 "promptEn": "scholar cornered but still defiant",
202   - "lastPlayedAt": 1788250669748
  202 + "lastPlayedAt": 1788253347544
203 203 },
204 204 {
205 205 "id": "bbf7efb467e0",
... ... @@ -364,7 +364,7 @@
364 364 "likes": 0,
365 365 "createdAt": 1788185090875,
366 366 "promptEn": "woman in white cold and threatening",
367   - "lastPlayedAt": 1788251808852
  367 + "lastPlayedAt": 1788253487611
368 368 },
369 369 {
370 370 "id": "a46f1daa9ee0",
... ... @@ -379,7 +379,7 @@
379 379 "likes": 0,
380 380 "createdAt": 1788181569491,
381 381 "promptEn": "a massive warship glides through the stars, the bridge suddenly shakes hard",
382   - "lastPlayedAt": 1788251214448
  382 + "lastPlayedAt": 1788253093423
383 383 },
384 384 {
385 385 "id": "44bf5b969e94",
... ... @@ -409,7 +409,7 @@
409 409 "likes": 0,
410 410 "createdAt": 1788160917846,
411 411 "promptEn": "woman in old chinese robe talking, gentle but wary, in an old room",
412   - "lastPlayedAt": 1788251177165
  412 + "lastPlayedAt": 1788253241500
413 413 },
414 414 {
415 415 "id": "24e49e5ae069",
... ... @@ -529,7 +529,7 @@
529 529 "likes": 0,
530 530 "createdAt": 1788120171725,
531 531 "promptEn": "constable bursts in and blocks the door, talks to a pale woman behind the screen",
532   - "lastPlayedAt": 1788249899449
  532 + "lastPlayedAt": 1788253571659
533 533 },
534 534 {
535 535 "id": "5c364152e54c",
... ... @@ -769,7 +769,7 @@
769 769 "likes": 0,
770 770 "createdAt": 1788026068497,
771 771 "promptEn": "black-haired prince in a red cloak, pressing down an execution order in the trial hall",
772   - "lastPlayedAt": 1788251740816
  772 + "lastPlayedAt": 1788253425586
773 773 },
774 774 {
775 775 "id": "0a5e37bb328c",
... ... @@ -799,7 +799,7 @@
799 799 "likes": 0,
800 800 "createdAt": 1788025640972,
801 801 "promptEn": "Voldemort in a graveyard, wand raised, stepping closer",
802   - "lastPlayedAt": 1788252161011
  802 + "lastPlayedAt": 1788253469603
803 803 },
804 804 {
805 805 "id": "c3875fbd6cc4",
... ... @@ -859,7 +859,7 @@
859 859 "likes": 0,
860 860 "createdAt": 1788025623833,
861 861 "promptEn": "cat-eared white-haired guard crouching in a ruined palace, purple aura around them",
862   - "lastPlayedAt": 1788251424585
  862 + "lastPlayedAt": 1788253528965
863 863 },
864 864 {
865 865 "id": "0d721acbc298",
... ... @@ -874,7 +874,7 @@
874 874 "likes": 0,
875 875 "createdAt": 1788025622363,
876 876 "promptEn": "detective in a surveillance room squinting at the monitors",
877   - "lastPlayedAt": 1788250159958
  877 + "lastPlayedAt": 1788253255505
878 878 },
879 879 {
880 880 "id": "639069dea7c5",
... ... @@ -949,7 +949,7 @@
949 949 "likes": 0,
950 950 "createdAt": 1788024747209,
951 951 "promptEn": "wounded hunter leaning on a subway turnstile, ordering you into the tunnel",
952   - "lastPlayedAt": 1788252002941
  952 + "lastPlayedAt": 1788253507622
953 953 },
954 954 {
955 955 "id": "fdefca4e4980",
... ... @@ -1114,7 +1114,7 @@
1114 1114 "likes": 0,
1115 1115 "createdAt": 1788014790969,
1116 1116 "promptEn": "pirate negotiation, stayed passive and got cornered",
1117   - "lastPlayedAt": 1788251730808
  1117 + "lastPlayedAt": 1788253191467
1118 1118 },
1119 1119 {
1120 1120 "id": "e14fe7c3220e",
... ... @@ -1144,7 +1144,7 @@
1144 1144 "likes": 0,
1145 1145 "createdAt": 1788014336515,
1146 1146 "promptEn": "captain's cabin on the Black Pearl, surrounded by pirates, negotiation could turn into an execution",
1147   - "lastPlayedAt": 1788250666207
  1147 + "lastPlayedAt": 1788253087383
1148 1148 },
1149 1149 {
1150 1150 "id": "eae105ee1204",
... ... @@ -1564,7 +1564,7 @@
1564 1564 "likes": 0,
1565 1565 "createdAt": 1788008632603,
1566 1566 "promptEn": "facing the Eternity Devil, went in head-on and got seen through",
1567   - "lastPlayedAt": 1788250580165
  1567 + "lastPlayedAt": 1788253502782
1568 1568 },
1569 1569 {
1570 1570 "id": "361c80537652",
... ... @@ -1669,7 +1669,7 @@
1669 1669 "likes": 0,
1670 1670 "createdAt": 1788006964122,
1671 1671 "promptEn": "grabbing an evidence flaw to counter L",
1672   - "lastPlayedAt": 1788251193178
  1672 + "lastPlayedAt": 1788253259502
1673 1673 },
1674 1674 {
1675 1675 "id": "0c6306b07f79",
... ... @@ -1699,7 +1699,7 @@
1699 1699 "likes": 0,
1700 1700 "createdAt": 1788006252918,
1701 1701 "promptEn": "facing L, stayed passive and the evidence pressure maxed out",
1702   - "lastPlayedAt": 1788251482641
  1702 + "lastPlayedAt": 1788253113430
1703 1703 },
1704 1704 {
1705 1705 "id": "0e28a7fecf03",
... ... @@ -1984,7 +1984,7 @@
1984 1984 "likes": 0,
1985 1985 "createdAt": 1788002217928,
1986 1986 "promptEn": "facing Reiner, stayed passive and got cornered",
1987   - "lastPlayedAt": 1788251696779
  1987 + "lastPlayedAt": 1788253551648
1988 1988 },
1989 1989 {
1990 1990 "id": "3fedf5531999",
... ... @@ -2029,7 +2029,7 @@
2029 2029 "likes": 0,
2030 2030 "createdAt": 1788001428705,
2031 2031 "promptEn": "in the ruins of Konoha, exploiting a flaw to counter Pain",
2032   - "lastPlayedAt": 1788251776833
  2032 + "lastPlayedAt": 1788253511622
2033 2033 },
2034 2034 {
2035 2035 "id": "e486fab4c24d",
... ... @@ -2044,7 +2044,7 @@
2044 2044 "likes": 0,
2045 2045 "createdAt": 1788001285796,
2046 2046 "promptEn": "in the ruins of Konoha, exploiting a flaw to counter Pain",
2047   - "lastPlayedAt": 1788252231046
  2047 + "lastPlayedAt": 1788253477606
2048 2048 },
2049 2049 {
2050 2050 "id": "808e89ca06a4",
... ... @@ -2104,7 +2104,7 @@
2104 2104 "likes": 0,
2105 2105 "createdAt": 1788000341927,
2106 2106 "promptEn": "Konoha destroyed by Shinra Tensei, Pain declaring order in the ruins",
2107   - "lastPlayedAt": 1788251102395
  2107 + "lastPlayedAt": 1788253434714
2108 2108 },
2109 2109 {
2110 2110 "id": "e245dbcc6d36",
... ... @@ -2254,7 +2254,7 @@
2254 2254 "likes": 0,
2255 2255 "createdAt": 1787847447661,
2256 2256 "promptEn": "constable tells the woman behind the screen he'll trust her tonight",
2257   - "lastPlayedAt": 1788250278003
  2257 + "lastPlayedAt": 1788253581662
2258 2258 },
2259 2259 {
2260 2260 "id": "8cb493338cb3",
... ... @@ -2314,7 +2314,7 @@
2314 2314 "likes": 0,
2315 2315 "createdAt": 1787762311804,
2316 2316 "promptEn": "constable sits with a cup of water, slowly looking up at the woman behind the screen",
2317   - "lastPlayedAt": 1788251410573
  2317 + "lastPlayedAt": 1788253411575
2318 2318 },
2319 2319 {
2320 2320 "id": "850f13881576",
... ... @@ -2374,7 +2374,7 @@
2374 2374 "likes": 0,
2375 2375 "createdAt": 1787730413689,
2376 2376 "promptEn": "constable grabs the oil lamp and hurls it at the portrait, the scroll catches fire",
2377   - "lastPlayedAt": 1788251572712
  2377 + "lastPlayedAt": 1788253556971
2378 2378 },
2379 2379 {
2380 2380 "id": "e6c23c6adc42",
... ... @@ -2509,7 +2509,7 @@
2509 2509 "likes": 0,
2510 2510 "createdAt": 1787708663418,
2511 2511 "promptEn": "constable catches his breath, thanks her, and rests on the couch while she watches",
2512   - "lastPlayedAt": 1788250466114
  2512 + "lastPlayedAt": 1788253353548
2513 2513 },
2514 2514 {
2515 2515 "id": "cd22c2b491fc",
... ... @@ -2584,7 +2584,7 @@
2584 2584 "likes": 0,
2585 2585 "createdAt": 1787708626228,
2586 2586 "promptEn": "constable drinks some water first, thanks her, watching the screen warily as he drinks",
2587   - "lastPlayedAt": 1788251160420
  2587 + "lastPlayedAt": 1788253265514
2588 2588 },
2589 2589 {
2590 2590 "id": "e08f7f7e54dd",
... ... @@ -2689,7 +2689,7 @@
2689 2689 "likes": 0,
2690 2690 "createdAt": 1787674737743,
2691 2691 "promptEn": "constable slowly looks around the room, discovers her watching him motionlessly through the screen",
2692   - "lastPlayedAt": 1788249837798
  2692 + "lastPlayedAt": 1788253445593
2693 2693 },
2694 2694 {
2695 2695 "id": "c74118d0413f",
... ... @@ -2824,7 +2824,7 @@
2824 2824 "likes": 0,
2825 2825 "createdAt": 1787674623678,
2826 2826 "promptEn": "constable bows to the screen, thanking her for sheltering him",
2827   - "lastPlayedAt": 1788251144418
  2827 + "lastPlayedAt": 1788253536965
2828 2828 },
2829 2829 {
2830 2830 "id": "d94991a1e21b",
... ... @@ -2929,7 +2929,7 @@
2929 2929 "likes": 0,
2930 2930 "createdAt": 1787665100787,
2931 2931 "promptEn": "constable politely asks the woman behind the screen for tea",
2932   - "lastPlayedAt": 1788250618187
  2932 + "lastPlayedAt": 1788253439598
2933 2933 },
2934 2934 {
2935 2935 "id": "d2c77b87b84b",
... ... @@ -2959,7 +2959,7 @@
2959 2959 "likes": 0,
2960 2960 "createdAt": 1787642579766,
2961 2961 "promptEn": "a summoner chants and calls a giant toad, which swallows the white-robed ghost whole",
2962   - "lastPlayedAt": 1788248777237
  2962 + "lastPlayedAt": 1788253597668
2963 2963 },
2964 2964 {
2965 2965 "id": "22a666455198",
... ... @@ -3079,7 +3079,7 @@
3079 3079 "likes": 0,
3080 3080 "createdAt": 1787615241814,
3081 3081 "promptEn": "xianxia character turning, only back and side profile shown",
3082   - "lastPlayedAt": 1788250526137
  3082 + "lastPlayedAt": 1788253329541
3083 3083 },
3084 3084 {
3085 3085 "id": "1a398591663e",
... ... @@ -3289,7 +3289,7 @@
3289 3289 "likes": 0,
3290 3290 "createdAt": 1787588540567,
3291 3291 "promptEn": "telescope view searching for a MiniMax device",
3292   - "lastPlayedAt": 1788248302814
  3292 + "lastPlayedAt": 1788253197469
3293 3293 },
3294 3294 {
3295 3295 "id": "ba8c0758e5b4",
... ... @@ -3304,7 +3304,7 @@
3304 3304 "likes": 0,
3305 3305 "createdAt": 1787588114381,
3306 3306 "promptEn": "underground rap duo freestyling at the camera",
3307   - "lastPlayedAt": 1788251744817
  3307 + "lastPlayedAt": 1788253391568
3308 3308 },
3309 3309 {
3310 3310 "id": "58a439a93c02",
... ... @@ -3349,7 +3349,7 @@
3349 3349 "likes": 0,
3350 3350 "createdAt": 1787577088778,
3351 3351 "promptEn": "man thanks the woman for taking him in",
3352   - "lastPlayedAt": 1788252149006
  3352 + "lastPlayedAt": 1788253473612
3353 3353 },
3354 3354 {
3355 3355 "id": "8d0270466c35",
... ... @@ -3364,7 +3364,7 @@
3364 3364 "likes": 0,
3365 3365 "createdAt": 1787576943673,
3366 3366 "promptEn": "man lowers his voice like she said, checks the door, window and lamp",
3367   - "lastPlayedAt": 1788251202953
  3367 + "lastPlayedAt": 1788253482789
3368 3368 },
3369 3369 {
3370 3370 "id": "396de15c1439",
... ... @@ -3379,7 +3379,7 @@
3379 3379 "likes": 0,
3380 3380 "createdAt": 1787576943608,
3381 3381 "promptEn": "man lowers his voice like she said, checks the door, window and lamp",
3382   - "lastPlayedAt": 1788249343532
  3382 + "lastPlayedAt": 1788253343544
3383 3383 },
3384 3384 {
3385 3385 "id": "cde82791f726",
... ... @@ -3454,7 +3454,7 @@
3454 3454 "likes": 0,
3455 3455 "createdAt": 1787576013870,
3456 3456 "promptEn": "man apologizes, says something outside was chasing him",
3457   - "lastPlayedAt": 1788241611137
  3457 + "lastPlayedAt": 1788253385557
3458 3458 },
3459 3459 {
3460 3460 "id": "7d425d2d35fb",
... ... @@ -3739,7 +3739,7 @@
3739 3739 "likes": 0,
3740 3740 "createdAt": 1787470099635,
3741 3741 "promptEn": "pointing at things at a beach market, they turn into hand-drawn animation",
3742   - "lastPlayedAt": 1788251368535
  3742 + "lastPlayedAt": 1788253516965
3743 3743 },
3744 3744 {
3745 3745 "id": "0fe0f2101c44",
... ... @@ -3844,7 +3844,7 @@
3844 3844 "likes": 0,
3845 3845 "createdAt": 1787452521817,
3846 3846 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
3847   - "lastPlayedAt": 1788249657655
  3847 + "lastPlayedAt": 1788253117433
3848 3848 },
3849 3849 {
3850 3850 "id": "f36cdd73ff1b",
... ... @@ -3859,7 +3859,7 @@
3859 3859 "likes": 0,
3860 3860 "createdAt": 1787450754171,
3861 3861 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
3862   - "lastPlayedAt": 1788249973852
  3862 + "lastPlayedAt": 1788253279519
3863 3863 },
3864 3864 {
3865 3865 "id": "fd0183c54763",
... ... @@ -3979,7 +3979,7 @@
3979 3979 "likes": 0,
3980 3980 "createdAt": 1787426955312,
3981 3981 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
3982   - "lastPlayedAt": 1788248098632
  3982 + "lastPlayedAt": 1788253219489
3983 3983 },
3984 3984 {
3985 3985 "id": "734d28c52670",
... ... @@ -4069,7 +4069,7 @@
4069 4069 "likes": 0,
4070 4070 "createdAt": 1787412952086,
4071 4071 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
4072   - "lastPlayedAt": 1788251143150
  4072 + "lastPlayedAt": 1788253367553
4073 4073 },
4074 4074 {
4075 4075 "id": "59fd7a087f5b",
... ... @@ -4084,7 +4084,7 @@
4084 4084 "likes": 0,
4085 4085 "createdAt": 1787412606465,
4086 4086 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
4087   - "lastPlayedAt": 1788251848870
  4087 + "lastPlayedAt": 1788253459597
4088 4088 },
4089 4089 {
4090 4090 "id": "29a99dc412b2",
... ... @@ -4174,7 +4174,7 @@
4174 4174 "likes": 0,
4175 4175 "createdAt": 1787384417941,
4176 4176 "promptEn": "protagonist leaps across rooftops fleeing pursuers",
4177   - "lastPlayedAt": 1788248669135
  4177 + "lastPlayedAt": 1788253405570
4178 4178 },
4179 4179 {
4180 4180 "id": "2cf5c8e67510",
... ... @@ -4219,7 +4219,7 @@
4219 4219 "likes": 0,
4220 4220 "createdAt": 1787375413623,
4221 4221 "promptEn": "golden portal opens, man in green jacket throws a glowing spear",
4222   - "lastPlayedAt": 1788250362064
  4222 + "lastPlayedAt": 1788253532966
4223 4223 },
4224 4224 {
4225 4225 "id": "78e698c924b1",
... ... @@ -4339,7 +4339,7 @@
4339 4339 "likes": 0,
4340 4340 "createdAt": 1787332047061,
4341 4341 "promptEn": "golden portal opens, man in green jacket throws a glowing spear",
4342   - "lastPlayedAt": 1788251350521
  4342 + "lastPlayedAt": 1788253407577
4343 4343 },
4344 4344 {
4345 4345 "id": "a5688d8f5db3",
... ... @@ -4354,7 +4354,7 @@
4354 4354 "likes": 0,
4355 4355 "createdAt": 1787330101793,
4356 4356 "promptEn": "a red apple on a wooden table, cinematic lighting",
4357   - "lastPlayedAt": 1788252205039
  4357 + "lastPlayedAt": 1788253473602
4358 4358 },
4359 4359 {
4360 4360 "id": "0024d3c2d4cb",
... ... @@ -4414,7 +4414,7 @@
4414 4414 "likes": 0,
4415 4415 "createdAt": 1787305544815,
4416 4416 "promptEn": "transparent gaming mouse product film, blue and orange lighting",
4417   - "lastPlayedAt": 1788251648757
  4417 + "lastPlayedAt": 1788253209480
4418 4418 },
4419 4419 {
4420 4420 "id": "e23b04ac2c78",
... ... @@ -4489,7 +4489,7 @@
4489 4489 "likes": 0,
4490 4490 "createdAt": 1787290119114,
4491 4491 "promptEn": "misty Jiangnan old town at dawn, woman walking with an oil-paper umbrella",
4492   - "lastPlayedAt": 1788248170701
  4492 + "lastPlayedAt": 1788253429580
4493 4493 },
4494 4494 {
4495 4495 "id": "0f22388f7847",
... ... @@ -4549,7 +4549,7 @@
4549 4549 "likes": 0,
4550 4550 "createdAt": 1787225897650,
4551 4551 "promptEn": "constable burns the beauty portrait with the lamp, the door opens on its own",
4552   - "lastPlayedAt": 1788247380017
  4552 + "lastPlayedAt": 1788253107430
4553 4553 },
4554 4554 {
4555 4555 "id": "ed3663dcda7f",
... ... @@ -4594,6 +4594,6 @@
4594 4594 "likes": 0,
4595 4595 "createdAt": 1787220579189,
4596 4596 "promptEn": "gothic castle at night, vampire noble carries a princess, rose petals falling",
4597   - "lastPlayedAt": 1788252092980
  4597 + "lastPlayedAt": 1788253381560
4598 4598 }
4599 4599 ]
4600 4600 \ No newline at end of file
... ...
live.html
... ... @@ -21,7 +21,7 @@
21 21 <div class="spacer"></div>
22 22 <div class="watching" id="watchingCount" hidden></div>
23 23 <button class="topbar-pill" id="chatToggleBtn">✕ 聊天</button>
24   - <button class="topbar-pill" id="muteBtn">🔇 静音</button>
  24 + <button class="topbar-pill" id="muteBtn">🔈 有声</button>
25 25 </header>
26 26  
27 27 <div class="body" id="body">
... ... @@ -38,7 +38,7 @@
38 38 <span class="np-time" id="nowPlayingTime"></span>
39 39 <div class="np-text" id="nowPlayingText">加载中…</div>
40 40 </div>
41   - <video id="player" autoplay muted playsinline></video>
  41 + <video id="player" autoplay playsinline></video>
42 42 </div>
43 43 </div>
44 44  
... ... @@ -114,6 +114,17 @@ muteBtn.addEventListener(&quot;click&quot;, () =&gt; {
114 114 muteBtn.textContent = player.muted ? "🔇 静音" : "🔈 有声";
115 115 });
116 116  
  117 +// Default to sound on. Chrome/Safari block unmuted autoplay without a prior
  118 +// user gesture on the site, so if the unmuted play() rejects, fall back to
  119 +// muted autoplay (always allowed) and let the button reflect the real state.
  120 +function tryPlay() {
  121 + player.play().catch(() => {
  122 + player.muted = true;
  123 + muteBtn.textContent = "🔇 静音";
  124 + player.play().catch(() => {});
  125 + });
  126 +}
  127 +
117 128 let chatClosed = false;
118 129 chatToggleBtn.addEventListener("click", () => {
119 130 chatClosed = !chatClosed;
... ... @@ -253,7 +264,7 @@ function playBrowse(index) {
253 264 currentIndex = index;
254 265 const c = clips[index];
255 266 player.src = `/lib/video/${c.id}`;
256   - player.play().catch(() => {});
  267 + tryPlay();
257 268 setNowPlaying(null, null, c.prompt);
258 269 renderBrowseList();
259 270 }
... ... @@ -360,7 +371,7 @@ function switchToClip(clip, offsetSec, requestedBy) {
360 371 { once: true }
361 372 );
362 373 }
363   - player.play().catch(() => {});
  374 + tryPlay();
364 375 setNowPlaying(requestedBy, fmtClock(Date.now()), clip.prompt);
365 376 }
366 377  
... ...