mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 20:24:27 -04:00
Add chapters on bottom scrubber, set video progress only on seek end
This commit is contained in:
parent
90498eb117
commit
1df8d6589a
@ -65,6 +65,7 @@ export const hoverAtom = atom((get) =>
|
|||||||
[!get(playAtom), ...Object.values(get(hoverReasonAtom))].includes(true),
|
[!get(playAtom), ...Object.values(get(hoverReasonAtom))].includes(true),
|
||||||
);
|
);
|
||||||
export const seekingAtom = atom(false);
|
export const seekingAtom = atom(false);
|
||||||
|
export const seekProgressAtom = atom<number | null>(null);
|
||||||
|
|
||||||
export const Hover = ({
|
export const Hover = ({
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -163,7 +164,7 @@ export const Hover = ({
|
|||||||
)}
|
)}
|
||||||
<ProgressBar chapters={chapters} url={url} />
|
<ProgressBar chapters={chapters} url={url} />
|
||||||
{showBottomSeeker ? (
|
{showBottomSeeker ? (
|
||||||
<BottomScrubber url={url} />
|
<BottomScrubber url={url} chapters={chapters} />
|
||||||
) : (
|
) : (
|
||||||
<View
|
<View
|
||||||
{...css({
|
{...css({
|
||||||
@ -329,25 +330,28 @@ const ProgressBar = ({ url, chapters }: { url: string; chapters?: Chapter[] }) =
|
|||||||
const setPlay = useSetAtom(playAtom);
|
const setPlay = useSetAtom(playAtom);
|
||||||
const [hoverProgress, setHoverProgress] = useState<number | null>(null);
|
const [hoverProgress, setHoverProgress] = useState<number | null>(null);
|
||||||
const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 });
|
const [layout, setLayout] = useState({ x: 0, y: 0, width: 0, height: 0 });
|
||||||
|
const [seekProgress, setSeekProgress] = useAtom(seekProgressAtom);
|
||||||
const setSeeking = useSetAtom(seekingAtom);
|
const setSeeking = useSetAtom(seekingAtom);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Slider
|
<Slider
|
||||||
progress={progress}
|
progress={seekProgress ?? progress}
|
||||||
startSeek={() => {
|
startSeek={() => {
|
||||||
setPlay(false);
|
setPlay(false);
|
||||||
setSeeking(true);
|
setSeeking(true);
|
||||||
}}
|
}}
|
||||||
endSeek={() => {
|
endSeek={() => {
|
||||||
setSeeking(false);
|
setSeeking(false);
|
||||||
|
setProgress(seekProgress!);
|
||||||
|
setSeekProgress(null);
|
||||||
setTimeout(() => setPlay(true), 10);
|
setTimeout(() => setPlay(true), 10);
|
||||||
}}
|
}}
|
||||||
onHover={(progress, layout) => {
|
onHover={(progress, layout) => {
|
||||||
setHoverProgress(progress);
|
setHoverProgress(progress);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
}}
|
}}
|
||||||
setProgress={setProgress}
|
setProgress={(progress) => setSeekProgress(progress)}
|
||||||
subtleProgress={buffered}
|
subtleProgress={buffered}
|
||||||
max={duration}
|
max={duration}
|
||||||
markers={chapters?.map((x) => x.startTime)}
|
markers={chapters?.map((x) => x.startTime)}
|
||||||
|
@ -23,10 +23,11 @@ import { Sprite, P, imageBorderRadius, ts } from "@kyoo/primitives";
|
|||||||
import { View, Platform } from "react-native";
|
import { View, Platform } from "react-native";
|
||||||
import { percent, useYoshiki, px, Theme, useForceRerender } from "yoshiki/native";
|
import { percent, useYoshiki, px, Theme, useForceRerender } from "yoshiki/native";
|
||||||
import { ErrorView } from "../../fetch";
|
import { ErrorView } from "../../fetch";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo } from "react";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { durationAtom, progressAtom } from "../state";
|
import { durationAtom } from "../state";
|
||||||
import { toTimerString } from "./left-buttons";
|
import { toTimerString } from "./left-buttons";
|
||||||
|
import { seekProgressAtom } from "./hover";
|
||||||
|
|
||||||
type Thumb = {
|
type Thumb = {
|
||||||
from: number;
|
from: number;
|
||||||
@ -147,17 +148,18 @@ export const ScrubberTooltip = ({
|
|||||||
};
|
};
|
||||||
let scrubberWidth = 0;
|
let scrubberWidth = 0;
|
||||||
|
|
||||||
export const BottomScrubber = ({ url }: { url: string }) => {
|
export const BottomScrubber = ({ url, chapters }: { url: string; chapters?: Chapter[] }) => {
|
||||||
const { css } = useYoshiki();
|
const { css } = useYoshiki();
|
||||||
const { info, error, stats } = useScrubber(url);
|
const { info, error, stats } = useScrubber(url);
|
||||||
const rerender = useForceRerender();
|
const rerender = useForceRerender();
|
||||||
|
|
||||||
const progress = useAtomValue(progressAtom);
|
const progress = useAtomValue(seekProgressAtom) ?? 0;
|
||||||
const duration = useAtomValue(durationAtom) ?? 1;
|
const duration = useAtomValue(durationAtom) ?? 1;
|
||||||
|
|
||||||
if (error) return <ErrorView error={error} />;
|
if (error) return <ErrorView error={error} />;
|
||||||
|
|
||||||
const width = stats?.width ?? 1;
|
const width = stats?.width ?? 1;
|
||||||
|
const chapter = chapters?.findLast((x) => x.startTime <= progress && progress < x.endTime);
|
||||||
return (
|
return (
|
||||||
<View {...css({ overflow: "hidden" })}>
|
<View {...css({ overflow: "hidden" })}>
|
||||||
<View
|
<View
|
||||||
@ -231,6 +233,7 @@ export const BottomScrubber = ({ url }: { url: string }) => {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{toTimerString(progress)}
|
{toTimerString(progress)}
|
||||||
|
{chapter && `\n${chapter.name}`}
|
||||||
</P>
|
</P>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -206,7 +206,12 @@ func (h *Handler) GetInfo(c echo.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Run extractors to have them in cache
|
||||||
h.extractor.RunExtractor(ret.Path, ret.Sha, &ret.Subtitles)
|
h.extractor.RunExtractor(ret.Path, ret.Sha, &ret.Subtitles)
|
||||||
|
h.thumbnails.ExtractThumbnail(
|
||||||
|
ret.Path,
|
||||||
|
fmt.Sprintf("%s/%s/thumbnails.png", resource, slug),
|
||||||
|
)
|
||||||
return c.JSON(http.StatusOK, ret)
|
return c.JSON(http.StatusOK, ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user