diff --git a/src/file-viewer/backend.tsx b/src/file-viewer/backend.tsx
index d744127ecd7194d8fffa276b878772dabef17ec8..5e1a17ecacd5f450bd366b39acaff25e9dd81a71 100644
--- a/src/file-viewer/backend.tsx
+++ b/src/file-viewer/backend.tsx
@@ -62,7 +62,6 @@ app.get("/file/*", async (c, next) => {
// The permissions system is currently binary, using the friend auth.
const permissions = FilePermissions.getByPrefix(rawFilePath);
if (permissions !== 0) {
- console.log(rawFilePath, getForFile(rawFilePath));
const friendAuthChallenge = requireFriendAuth(c, getForFile(rawFilePath));
if (friendAuthChallenge) return friendAuthChallenge;
}
diff --git a/src/global.css b/src/global.css
index 95cfa646e7c3830b7d9132e6f9bc7829dd973e1b..820be21ef2c35f45730d4075e35eec89ba575a32 100644
--- a/src/global.css
+++ b/src/global.css
@@ -66,8 +66,10 @@ body {
}
main {
+ display: block;
margin: auto;
- max-width: 80ch;
+ width: auto;
+ max-width: 768px;
padding: 1em;
}
@@ -86,7 +88,7 @@ figure,
ul,
ol {
margin-top: 1em;
- margin-bottom: 1rem;
+ margin-bottom: 1em;
}
ul,
@@ -100,11 +102,15 @@ li {
a {
text-decoration: none;
+ color: var(--primary);
+}
+a.custom {
+ color: inherit;
}
a:where([href]:not(.custom)) {
color: var(--primary);
- margin: -0.2rem -0.3rem;
- padding: 0.2rem 0.3rem;
+ margin: -0.2em -0.3em;
+ padding: 0.2em 0.3em;
border-radius: 4px;
&:hover {
text-decoration: underline;
diff --git a/src/pages/history-of-japan-reanimated.client.ts b/src/pages/history-of-japan-reanimated.client.ts
index 2d053ec6dd77136c34766e0529c91d8beda2f2a2..d9d1f3d0f3fe93365ac7ef0ccadfb443d98f0064 100644
--- a/src/pages/history-of-japan-reanimated.client.ts
+++ b/src/pages/history-of-japan-reanimated.client.ts
@@ -124,7 +124,6 @@ function updateCredits(video) {
}
globalThis.onCloverVideoInit = (id: string, video: HTMLVideoElement) => {
- console.log(1, id, video);
if (id === "main-player") {
updateCredits(video);
video.addEventListener("timeupdate", () => {
diff --git a/src/pages/history-of-japan-reanimated.marko b/src/pages/history-of-japan-reanimated.marko
index 4a860cadfb02c35520a19948b14436074f915d9d..863671af05effeabb78a1b6b6b00b751f8099108 100644
--- a/src/pages/history-of-japan-reanimated.marko
+++ b/src/pages/history-of-japan-reanimated.marko
@@ -26,7 +26,7 @@ export const theme = {
me and 16 other artists (music, narration, and animation) have been
spending the past couple months on a recreation of bill wurtz's legendary
"history of japan" to celebrate the 10 year anniversary of his release. i
- contributed two animation sections. the canonical release is on
+ contributed two animation sections. the canonical release is on
LunaPogi's YouTube page, but i
am providing this ad-free video player.
@@ -49,22 +49,22 @@ export const theme = {
- Kappacap - thumbnail artist
- - atamai - animation (0:03-1:02)>
- - moxley - music and narration (0:03-3:10)>, animation (3:51-4:03)>
- - TheJustinator - animation (1:03-1:33, 2:02-2:33)>, music (3:11-6:04)>
- - chaosyumi - animation (1:34-2:01, 5:34-6:05)>
- - LunaPogi - animation (3:36-3:51, 8:01-9:10)>, music (6:05-9:10)>, narration (8:01-9:10)>
- - zeccet (bgongo) - animation (2:23-3:10)>
- - TheRealTinyWorld - animation (3:11-3:35)>
- - Fred French VA - narration (3:11-4:35)>
- - rqfirqfo - animation (4:04-4:35)>
- - krispykarim - animation (4:36 - 5:04)>, narration (4:36-8:01)>
- - SimplyDoodled Studios - animation (5:05-5:33)>
- - paper clover (me) - animation (6:05-6:38)>, credits animation (9:11-9:35)>
- - Coffee - transcription (6:05-9:10)>
- - harjjw - animation (6:38-7:03)>
- - yellowmarkers - animation (7:04-7:36)>
- - TheNothingGuy07 - animation (7:37-7:59)>
+ - atamai - animation (0:03-1:02)>
+ - moxley - music and narration (0:03-3:10)>, animation (3:51-4:03)>
+ - TheJustinator - animation (1:03-1:33, 2:02-2:33)>, music (3:11-6:04)>
+ - chaosyumi - animation (1:34-2:01, 5:34-6:05)>
+ - LunaPogi - animation (3:36-3:51, 8:01-9:10)>, music (6:05-9:10)>, narration (8:01-9:10)>
+ - zeccet (bgongo) - animation (2:23-3:10)>
+ - TheRealTinyWorld - animation (3:11-3:35)>
+ - Fred French VA - narration (3:11-4:35)>
+ - rqfirqfo - animation (4:04-4:35)>
+ - krispykarim - animation (4:36 - 5:04)>, narration (4:36-8:01)>
+ - SimplyDoodled Studios - animation (5:05-5:33)>
+ - paper clover (me) - animation (6:05-6:38)>, credits animation (9:11-9:35)>
+ - Coffee - transcription (6:05-9:10)>
+ - harjjw - animation (6:38-7:03)>
+ - yellowmarkers - animation (7:04-7:36)>
+ - TheNothingGuy07 - animation (7:37-7:59)>
diff --git a/src/pages/index.css b/src/pages/index.css
index c9e4176e75d230808f12088236a0e974f1bc8cf9..bd1994a8235c8cc4aa772fa4ad748c2c10339405 100644
--- a/src/pages/index.css
+++ b/src/pages/index.css
@@ -4,7 +4,7 @@ main {
flex-direction: column;
justify-content: center;
align-items: center;
- height: 100vh;
+ min-height: 100vh;
& > div {
width: 450px;
margin: auto;
diff --git a/src/q+a/views/permalink.marko b/src/q+a/views/permalink.marko
index b9e2d3d602e239c3170547124181a437b15de461..64500a56967d3c20419c02f2fd63a22134673a53 100644
--- a/src/q+a/views/permalink.marko
+++ b/src/q+a/views/permalink.marko
@@ -4,7 +4,6 @@ export interface Input {
}
server export function meta({ context, question }) {
- console.log(context.req.header("user-agent"));
const isDiscord = context.req.header("user-agent")
?.toLowerCase()
.includes("discord");
diff --git a/src/tags/clover-video.client.ts b/src/tags/clover-video.client.ts
index 0c33bd467afa2e79298b8e0456d6db6d753a7721..8337506fd8f89f75ade682d2b0c058fe8fb37ab6 100644
--- a/src/tags/clover-video.client.ts
+++ b/src/tags/clover-video.client.ts
@@ -2,6 +2,12 @@
// Polyfill for old browsers.
type PlaybackMode = "av1" | "hls-polyfill" | "hls-native" | "none";
+declare global {
+ function hydrateVideo(container: HTMLElement): void;
+ var ManagedMediaSource: typeof MediaSource | null;
+ var onCloverVideoInit: null | ((id: string, video: HTMLVideoElement) => void);
+}
+
const forceMode = location.search.match(/(?:\?|&)force-player=(.*)/)?.[1] as
| PlaybackMode
| undefined;
@@ -16,7 +22,6 @@ Promise.allSettled ??= (promises: Iterable>) =>
(reason) => ({ status: "rejected" as const, reason }),
)));
-declare function hydrateVideo(container: HTMLElement): void;
globalThis.hydrateVideo = function hydrateVideo(container) {
mode ??= decidePlaybackMode();
mode.then((mode) => hydrateVideoInner(container, mode));
@@ -27,9 +32,6 @@ Array.from(
(container) => hydrateVideo(container),
);
-// TODO: be less stupid about this
-const onCloverVideoInit = window.onCloverVideoInit;
-
function decidePlaybackMode(): Promise {
if (forceMode) {
if (forceMode === "hls-polyfill") {
@@ -49,27 +51,41 @@ function decidePlaybackMode(): Promise {
// Software decoding is too slow to use, unfortunately.
// Consider a device like a 2014 two core laptop.
console.warn(`implements non-accelerated av1+opus`);
+
+ // but on my slow Windows 7 laptop on Chrome, the HLS polyfill lags
+ // even on stable internet, so the av1 encoder ends up being better.
+ if (navigator.platform === "Win32") {
+ const chromeVersion = /Chrome\/(\d+)/.exec(navigator.userAgent)?.[1];
+ if (chromeVersion && Number(chromeVersion) < 110) {
+ console.warn("using av1 since win32 chrome runs hls.js badly");
+ return "none";
+ }
+ }
} else {
console.warn(`does not implement av1+opus`);
}
- // Native HLS support (Safari v6)
- const video = document.querySelector("video")!;
- if (video.canPlayType("application/x-mpegURL")) {
- return "hls-native";
- }
-
- // @ts-expect-error
- return (hls ??= import("/js/scripts/vendor/hls.js"))
- .then((hls): PlaybackMode => {
- // Polyfill HLS (Chrome 23, Firefox 42, IE11 on Win8)
- // TODO: ES modules have a minimum of Chrome 63 or Firefox 60
- if (hls.default.isSupported()) return "hls-polyfill";
- // Other browsers
- return "none";
- });
+ return canNativelyPlayHls().then((nativeHls): PlaybackMode => {
+ if (nativeHls) return "hls-native";
+ // @ts-expect-error
+ return (hls ??= import("/js/scripts/vendor/hls.js"))
+ .then((hls): PlaybackMode => {
+ // Polyfill HLS (Chrome 23, Firefox 42, IE11 on Win8)
+ // TODO: ES modules have a minimum of Chrome 63 or Firefox 60
+ if (hls?.default?.isSupported?.() || hls?.isSupported()) {
+ return "hls-polyfill";
+ }
+ console.warn("does not support hls.js");
+ // Other browsers
+ return "none";
+ });
+ });
+ })
+ .catch((e): PlaybackMode => {
+ console.warn(e);
+ console.warn("falling back to default player");
+ return "none";
})
- .catch((): PlaybackMode => "none")
.then((mode) => {
console.info(`selected playback mode: ${mode}`);
return mode;
@@ -115,7 +131,8 @@ function hydrateVideoInner(
enableSafariAirplay();
player.initialize(video, dashFile, false);
video.controls = true;
- onCloverVideoInit?.(id, video);
+ // TODO: be less stupid about this
+ window.onCloverVideoInit?.(id, video);
return;
}
@@ -219,7 +236,6 @@ function hydrateVideoInner(
onCloverVideoInit?.(id, video);
} else if (mode === "hls-polyfill") {
hls!.then((hls) => {
- console.log(hls);
// @ts-expect-error suspicious
const player = new (hls.default ?? hls.Hls)();
player.loadSource(hlsFile);
@@ -234,7 +250,6 @@ function hydrateVideoInner(
}
}
-declare var ManagedMediaSource: typeof MediaSource | null;
function shouldPlayAv1(): Promise<{ hardware: boolean; supported: boolean }> {
const MediaSource = globalThis.ManagedMediaSource ?? globalThis.MediaSource;
if (!MediaSource.isTypeSupported('audio/webm;codecs="opus"')) {
@@ -268,3 +283,29 @@ function shouldPlayAv1(): Promise<{ hardware: boolean; supported: boolean }> {
}));
}
}
+
+function canNativelyPlayHls() {
+ const video = document.createElement("video");
+ const canPlay = video.canPlayType("application/x-mpegURL");
+
+ if (!canPlay) return Promise.resolve(false);
+
+ return new Promise((resolve) => {
+ video.src = "data:application/x-mpegURL,#EXTM3U";
+ video.load();
+
+ function cleanup() {
+ clearTimeout(timeout);
+ video.removeEventListener("error", onError);
+ video.removeEventListener("loadedmetadata", onLoad);
+ video.src = "";
+ }
+
+ const onError = () => (cleanup(), resolve(false));
+ const onLoad = () => (cleanup(), resolve(true));
+ const timeout = setTimeout(onError, 100);
+
+ video.addEventListener("error", onError);
+ video.addEventListener("loadedmetadata", onLoad);
+ });
+}