add WatchPage customization
This commit is contained in:
parent
62d10aa608
commit
26d4b99d2d
2 changed files with 254 additions and 0 deletions
|
@ -1 +1,3 @@
|
|||
currently only supports a ``--debug``` flag
|
||||
|
||||
WatchpPage.tsx is a customized version of https://github.com/ragtag-archive/archive-browser/blob/master/modules/WatchPage.tsx to support webm delivery for Firefox Users - is wonky but works (kinda).
|
||||
|
|
252
WatchPage.tsx
Normal file
252
WatchPage.tsx
Normal file
|
@ -0,0 +1,252 @@
|
|||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import PageBase from "./shared/PageBase";
|
||||
import { VideoMetadata } from "./shared/database.d";
|
||||
import { formatDate } from "./shared/format";
|
||||
import ChatReplayPanel from "./shared/ChatReplay/ChatReplayPanel";
|
||||
import VideoCard from "./shared/VideoCard";
|
||||
import Link from "next/link";
|
||||
import ServiceUnavailablePage from "./ServiceUnavailablePage";
|
||||
import VideoActionButtons from "./shared/VideoActionButtons";
|
||||
import { useWindowSize } from "./shared/hooks/useWindowSize";
|
||||
import MemoLinkify from "./shared/MemoLinkify";
|
||||
import VideoPlayerHead from "./shared/VideoPlayerHead";
|
||||
import ClientRender from "./shared/ClientRender";
|
||||
import VideoPlayer2 from "./shared/VideoPlayer/VideoPlayer2";
|
||||
import ExpandableContainer from "./ExpandableContainer";
|
||||
import CommentSection from "./CommentSection";
|
||||
|
||||
const format = (n: number) => Intl.NumberFormat("en-US").format(n);
|
||||
|
||||
export type WatchPageProps = {
|
||||
videoInfo: VideoMetadata;
|
||||
hasChat: boolean;
|
||||
relatedVideos: VideoMetadata[];
|
||||
channelVideoCount: number;
|
||||
channelProfileURL: string;
|
||||
};
|
||||
|
||||
const getFile = (videoInfo: VideoMetadata, suffix: string) =>
|
||||
videoInfo.files.find((file) => file.name.includes(suffix))?.url;
|
||||
|
||||
const WatchPage = (props: WatchPageProps) => {
|
||||
if (!props.videoInfo) return <ServiceUnavailablePage />;
|
||||
|
||||
const { videoInfo, hasChat, relatedVideos } = props;
|
||||
|
||||
const [isChatVisible, setIsChatVisible] = React.useState(false);
|
||||
const refMobileScrollTarget = React.useRef<HTMLDivElement>(null);
|
||||
const { innerWidth, innerHeight } = useWindowSize();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isChatVisible)
|
||||
refMobileScrollTarget.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}, [isChatVisible]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!videoInfo || window.location.host.startsWith("localhost")) return;
|
||||
fetch(
|
||||
"/api/pv?channel_id=" +
|
||||
videoInfo.channel_id +
|
||||
"&video_id=" +
|
||||
videoInfo.video_id
|
||||
);
|
||||
}, [videoInfo]);
|
||||
|
||||
const [playbackProgress, setPlaybackProgress] = React.useState(0);
|
||||
/*const [fmtVideo, fmtAudio] = videoInfo.format_id.split("+");
|
||||
const urlVideo = getFile(videoInfo, ".f" + fmtVideo);
|
||||
const urlAudio = getFile(videoInfo, ".f" + fmtAudio);*/
|
||||
const urlVideo = getFile(videoInfo, ".mkv");
|
||||
const urlAudio = '';
|
||||
// srcAudio={urlAudio}
|
||||
|
||||
const urlThumb = getFile(videoInfo, ".webp") || getFile(videoInfo, ".jpg");
|
||||
const urlChat = getFile(videoInfo, ".chat.json");
|
||||
const urlInfo = getFile(videoInfo, ".info.json");
|
||||
|
||||
// Function to check if the user agent is Firefox
|
||||
const isFirefox = typeof window !== 'undefined' && navigator.userAgent.includes('Firefox');
|
||||
|
||||
// Update the video URL if it's Firefox and the URL ends with .mkv
|
||||
let updatedVideoUrl = urlVideo;
|
||||
|
||||
if (isFirefox && urlVideo.endsWith('.mkv')) {
|
||||
// For Firefox, rewrite to .webm and prepend /convert/
|
||||
updatedVideoUrl = urlVideo.replace('/vpath/', '/convert/vpath/').replace('.mkv', '.webm');
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
console.log('User Agent:', navigator.userAgent);
|
||||
console.log('Is Firefox:', isFirefox);
|
||||
console.log('Updated Video URL because Firefox beeing special (https://bugzilla.mozilla.org/show_bug.cgi?id=1422891):', updatedVideoUrl);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageBase>
|
||||
<VideoPlayerHead videoInfo={videoInfo} />
|
||||
<div
|
||||
className={["flex lg:flex-row flex-col lg:h-auto"].join(" ")}
|
||||
style={{
|
||||
height: isChatVisible && innerWidth < 640 ? innerHeight : "auto",
|
||||
}}
|
||||
>
|
||||
<div className="w-full lg:w-3/4">
|
||||
<div className="lg:absolute lg:top-0" ref={refMobileScrollTarget} />
|
||||
<div
|
||||
className="relative bg-gray-400 h-0"
|
||||
style={{ paddingBottom: "56.25%" }}
|
||||
>
|
||||
<div className="absolute inset-0 w-full h-full">
|
||||
<VideoPlayer2
|
||||
key={updatedVideoUrl}
|
||||
videoId={videoInfo.id}
|
||||
srcVideo={updatedVideoUrl}
|
||||
srcPoster={urlThumb}
|
||||
captions={videoInfo.files
|
||||
.filter((file) => file.name.endsWith(".ytt"))
|
||||
.map(({ name }) => {
|
||||
const lang = name.split(".")[1];
|
||||
return {
|
||||
lang,
|
||||
src: getFile(videoInfo, name),
|
||||
};
|
||||
})}
|
||||
onPlaybackProgress={setPlaybackProgress}
|
||||
autoplay
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={[
|
||||
"w-full lg:w-1/4 lg:pl-4",
|
||||
isChatVisible ? "flex-1" : "",
|
||||
].join(" ")}
|
||||
>
|
||||
{!hasChat ? (
|
||||
<div className="border border-gray-800 rounded p-4 text-center">
|
||||
<p>Chat replay unavailable</p>
|
||||
</div>
|
||||
) : (
|
||||
<ChatReplayPanel
|
||||
src={urlChat}
|
||||
currentTimeSeconds={playbackProgress}
|
||||
onChatToggle={setIsChatVisible}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex lg:flex-row flex-col">
|
||||
<div className="w-full lg:w-3/4">
|
||||
<div className="mt-4 mx-6">
|
||||
<h1 className="text-2xl mb-2">{videoInfo.title}</h1>
|
||||
<div className="flex flex-row justify-between">
|
||||
<ClientRender enableSSR>
|
||||
<p className="text-gray-400">
|
||||
{format(videoInfo.view_count)} views ·{" "}
|
||||
<span
|
||||
title={
|
||||
videoInfo.timestamps?.publishedAt
|
||||
? new Date(
|
||||
videoInfo.timestamps?.publishedAt
|
||||
).toLocaleString()
|
||||
: "(exact timestamp unknown)"
|
||||
}
|
||||
>
|
||||
Uploaded{" "}
|
||||
{formatDate(
|
||||
new Date(
|
||||
videoInfo.timestamps?.publishedAt ||
|
||||
videoInfo.upload_date
|
||||
)
|
||||
)}
|
||||
</span>{" "}
|
||||
·{" "}
|
||||
<span
|
||||
title={new Date(
|
||||
videoInfo.archived_timestamp +
|
||||
(videoInfo.archived_timestamp.endsWith("Z") ? "" : "Z")
|
||||
).toLocaleString()}
|
||||
>
|
||||
Archived{" "}
|
||||
{formatDate(
|
||||
new Date(
|
||||
videoInfo.archived_timestamp +
|
||||
(videoInfo.archived_timestamp.endsWith("Z")
|
||||
? ""
|
||||
: "Z")
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
</ClientRender>
|
||||
<div>
|
||||
<span className="text-green-500">
|
||||
{format(videoInfo.like_count)} likes
|
||||
</span>{" "}
|
||||
/{" "}
|
||||
<span className="text-red-500">
|
||||
{format(videoInfo.dislike_count)} dislikes
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row mt-2">
|
||||
<VideoActionButtons full video={videoInfo} />
|
||||
</div>
|
||||
<div className="mt-4 pb-4 border-b border-gray-900">
|
||||
<div className="inline-block">
|
||||
<Link href={"/channel/" + videoInfo.channel_id}>
|
||||
<a className="mb-4 mb-4 hover:underline flex flex-row">
|
||||
<div className="w-12 h-12 rounded-full overflow-hidden relative">
|
||||
<Image
|
||||
priority
|
||||
alt="Channel thumbnail"
|
||||
src={"https://i.imgur.com/rBvryFM.png"||props.channelProfileURL}
|
||||
layout="fixed"
|
||||
width={48}
|
||||
height={48}
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-4">
|
||||
<p className="font-bold text-lg leading-tight">
|
||||
{videoInfo.channel_name}
|
||||
</p>
|
||||
<span className="text-gray-400 leading-tight">
|
||||
{props.channelVideoCount} videos
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<ExpandableContainer>
|
||||
<div className="whitespace-pre-line break-words text-gray-300">
|
||||
<MemoLinkify linkClassName="text-blue-300 hover:underline focus:outline-none focus:underline">
|
||||
{videoInfo.description}
|
||||
</MemoLinkify>
|
||||
</div>
|
||||
</ExpandableContainer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/4 lg:pl-4">
|
||||
<div className="mt-6">
|
||||
<h2 className="text-xl font-bold mb-2">Related videos</h2>
|
||||
<div>
|
||||
{relatedVideos.map((video) => (
|
||||
<div className="mb-4" key={video.video_id}>
|
||||
<VideoCard small video={video} key={video.video_id} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageBase>
|
||||
);
|
||||
};
|
||||
|
||||
export default WatchPage;
|
Loading…
Add table
Reference in a new issue