fixed positioning and added loading icon

This commit is contained in:
frost768 2023-06-10 14:38:26 +03:00
parent 1ade111757
commit 4a36f98bf4
4 changed files with 63 additions and 39 deletions

View File

@ -34,6 +34,10 @@ body[data-no-select] {
animation: roll 1s;
}
.roll-infinite {
animation: roll 2s infinite;
}
@keyframes roll {
from {
transform: rotate(0deg);

View File

@ -3,11 +3,14 @@ export interface Thumbnail {
to: number;
imgUrl: string;
}
export const SCALE_FACTOR = 0.1;
export const SCALE_FACTOR = 1;
export default async function* extractThumbnails(
videoUrl: string,
numThumbnails: number
): AsyncGenerator<Thumbnail, Thumbnail> {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) return { from: -1, to: -1, imgUrl: "" };
const video = document.createElement("video");
video.src = videoUrl;
video.crossOrigin = "anonymous";
@ -18,12 +21,8 @@ export default async function* extractThumbnails(
video.addEventListener("error", reject);
});
const canvas = document.createElement("canvas");
canvas.height = video.videoHeight * SCALE_FACTOR;
canvas.width = video.videoWidth * SCALE_FACTOR;
const ctx = canvas.getContext("2d");
if (!ctx) return { from: 0, to: 0, imgUrl: "" };
for (let i = 0; i <= numThumbnails; i += 1) {
const from = (i / (numThumbnails + 1)) * video.duration;
@ -48,5 +47,5 @@ export default async function* extractThumbnails(
};
}
return { from: 0, to: 0, imgUrl: "" };
return { from: -1, to: -1, imgUrl: "" };
}

View File

@ -70,9 +70,11 @@ export function ProgressAction() {
);
return (
<div className="group pointer-events-auto w-full cursor-pointer rounded-full px-2">
<div
ref={ref}
className="group pointer-events-auto w-full cursor-pointer rounded-full px-2"
>
<div
ref={ref}
className="-my-3 flex h-8 items-center"
onMouseDown={dragMouseDown}
onTouchStart={dragMouseDown}
@ -101,16 +103,16 @@ export function ProgressAction() {
dragging ? "!scale-[400%] !opacity-100" : ""
}`}
/>
{isThumbnailVisible ? (
<ThumbnailAction
parentRef={ref}
videoTime={videoTime}
hoverPosition={hoverPosition}
/>
) : null}
</div>
</div>
</div>
{isThumbnailVisible ? (
<ThumbnailAction
parentRef={ref}
videoTime={videoTime}
hoverPosition={hoverPosition}
/>
) : null}
</div>
);
}

View File

@ -1,11 +1,13 @@
import { RefObject } from "react";
import { Icon, Icons } from "@/components/Icon";
import { formatSeconds } from "@/utils/formatSeconds";
import { SCALE_FACTOR } from "@/utils/thumbnailCreator";
import { useVideoPlayerDescriptor } from "@/video/state/hooks";
import { VideoProgressEvent } from "@/video/state/logic/progress";
import { useSource } from "@/video/state/logic/source";
const THUMBNAIL_HEIGHT = 100;
export default function ThumbnailAction({
parentRef,
hoverPosition,
@ -18,44 +20,61 @@ export default function ThumbnailAction({
const descriptor = useVideoPlayerDescriptor();
const source = useSource(descriptor);
if (!parentRef.current) return null;
const offset =
(document.getElementsByTagName("video")[0].videoWidth * SCALE_FACTOR) / 2;
const videoEl = document.getElementsByTagName("video")[0];
const aspectRatio = videoEl.videoWidth / videoEl.videoHeight;
const rect = parentRef.current.getBoundingClientRect();
if (!rect.width) return null;
const hoverPercent = (hoverPosition - rect.left) / rect.width;
const hoverTime = videoTime.duration * hoverPercent;
const thumbnailWidth = THUMBNAIL_HEIGHT * aspectRatio;
const pos = () => {
const relativePosition = hoverPosition - rect.left;
if (relativePosition <= offset) {
return 0;
if (relativePosition <= thumbnailWidth / 2) {
return rect.left;
}
if (relativePosition >= rect.width - offset) {
return rect.width - offset * 2;
if (relativePosition >= rect.width - thumbnailWidth / 2) {
return rect.width + rect.left - thumbnailWidth;
}
return relativePosition - offset;
return relativePosition + rect.left - thumbnailWidth / 2;
};
const src = source.source?.thumbnails.find(
(x) => x.from < hoverTime && x.to > hoverTime
)?.imgUrl;
return (
<div>
<img
style={{
left: `${pos()}px`,
}}
className="absolute bottom-10 rounded"
src={
source.source?.thumbnails.find(
(x) => x.from < hoverTime && x.to > hoverTime
)?.imgUrl
}
/>
<div className="text-center">
{!src ? (
<div
style={{
left: `${pos()}px`,
width: `${thumbnailWidth}px`,
height: `${THUMBNAIL_HEIGHT}px`,
}}
className="absolute bottom-32 flex items-center justify-center rounded bg-black"
>
<Icon
className="roll-infinite text-6xl text-bink-600"
icon={Icons.MOVIE_WEB}
/>
</div>
) : (
<img
height={THUMBNAIL_HEIGHT}
width={thumbnailWidth}
style={{
left: `${pos()}px`,
}}
className="absolute bottom-32 rounded"
src={src}
/>
)}
<div
style={{
left: `${pos() + offset - 18}px`,
left: `${pos() + thumbnailWidth / 2 - 18}px`,
}}
className="absolute bottom-3 text-white"
className="absolute bottom-24 text-white"
>
{formatSeconds(hoverTime)}
{formatSeconds(hoverTime, videoEl.duration > 60 * 60)}
</div>
</div>
);