fixed sub issues

This commit is contained in:
PhilReact 2025-06-15 23:25:49 +03:00
parent 0e6a5e14a9
commit 793449f486
5 changed files with 361 additions and 173 deletions

View File

@ -1,4 +1,10 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
QortalGetMetadata,
QortalMetadata,
@ -10,6 +16,7 @@ import {
Button,
ButtonBase,
Card,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
@ -18,9 +25,11 @@ import {
Fade,
IconButton,
Popover,
Skeleton,
Tab,
Tabs,
Typography,
useTheme,
} from "@mui/material";
import CheckIcon from "@mui/icons-material/Check";
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
@ -43,6 +52,12 @@ import { ResourceToPublish } from "../../types/qortalRequests/types";
import { useListReturn } from "../../hooks/useListData";
import { usePublish } from "../../hooks/usePublish";
import { Spacer } from "../../common/Spacer";
import {
dismissToast,
showError,
showLoading,
showSuccess,
} from "../../utils/toast";
interface SubtitleManagerProps {
qortalMetadata: QortalGetMetadata;
close: () => void;
@ -90,28 +105,36 @@ const SubtitleManagerComponent = ({
const [mode, setMode] = useState(1);
const [isOpenPublish, setIsOpenPublish] = useState(false);
const { lists, identifierOperations, auth } = useGlobal();
const [isLoading, setIsLoading] = useState(false);
const [showAll, setShowAll] = useState(false);
const { fetchResources } = useResources();
// const [subtitles, setSubtitles] = useState([])
const subtitles = useListReturn(
`subs-${qortalMetadata?.service}-${qortalMetadata?.name}-${qortalMetadata?.identifier}`
);
console.log('subtitles222', subtitles)
const mySubtitles = useMemo(()=> {
if(!auth?.name)return []
return subtitles?.filter((sub)=> sub.name === auth?.name)
}, [subtitles, auth?.name])
console.log("subtitles222", subtitles);
const mySubtitles = useMemo(() => {
if (!auth?.name) return [];
return subtitles?.filter((sub) => sub.name === auth?.name);
}, [subtitles, auth?.name]);
console.log("subtitles222", subtitles);
const getPublishedSubtitles = useCallback(async () => {
try {
setIsLoading(true);
const videoId = `${qortalMetadata?.service}-${qortalMetadata?.name}-${qortalMetadata?.identifier}`;
console.log("videoId", videoId);
const postIdSearch = await identifierOperations.buildSearchPrefix(
ENTITY_SUBTITLE,
videoId
);
let name: string | undefined = qortalMetadata?.name;
if (showAll) {
name = undefined;
}
const searchParams = {
service: SERVICE_SUBTITLE,
identifier: postIdSearch,
name,
limit: 0,
};
const res = await lists.fetchResources(
@ -123,8 +146,10 @@ const SubtitleManagerComponent = ({
console.log("resres2", res);
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
}, []);
}, [showAll]);
useEffect(() => {
if (
@ -215,6 +240,8 @@ const SubtitleManagerComponent = ({
close();
};
const theme = useTheme();
return (
<>
<Popover
@ -236,7 +263,11 @@ const SubtitleManagerComponent = ({
borderRadius: 2,
boxShadow: 5,
p: 1,
minWidth: 200,
minWidth: 225,
height: 300,
overflow: "hidden",
display: "flex",
flexDirection: "column",
},
},
}}
@ -288,7 +319,49 @@ const SubtitleManagerComponent = ({
</ButtonBase>
</Box>
<Divider />
{mode === 1 && (
<Box
sx={{
display: "flex",
flexDirection: "column",
flexGrow: 1,
overflow: "auto",
"::-webkit-scrollbar-track": {
backgroundColor: "transparent",
},
"::-webkit-scrollbar": {
width: "16px",
height: "10px",
},
"::-webkit-scrollbar-thumb": {
backgroundColor: theme.palette.primary.main,
borderRadius: "8px",
backgroundClip: "content-box",
border: "4px solid transparent",
transition: "0.3s background-color",
},
"::-webkit-scrollbar-thumb:hover": {
backgroundColor: theme.palette.primary.dark,
},
}}
>
{isLoading && <CircularProgress />}
{!isLoading && subtitles?.length === 0 && (
<Typography
sx={{
fontSize: "1rem",
width: "100%",
textAlign: "center",
marginTop: "20px",
}}
>
No subtitles
</Typography>
)}
{mode === 1 && !isLoading && subtitles?.length > 0 && (
<PublisherSubtitles
subtitles={subtitles}
publisherName={qortalMetadata.name}
@ -298,6 +371,23 @@ const SubtitleManagerComponent = ({
currentSubTrack={currentSubTrack}
/>
)}
</Box>
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "center",
}}
>
<Button
variant="contained"
size="small"
disabled={showAll}
onClick={() => setShowAll(true)}
>
Load all
</Button>
</Box>
{/* <Box>
{[
'Ambient mode',
@ -414,6 +504,23 @@ const PublisherSubtitles = ({
}: PublisherSubtitlesProps) => {
return (
<>
<ButtonBase
disabled={!currentSubTrack}
onClick={() => onSelect(null)}
sx={{
px: 2,
py: 1,
"&:hover": {
backgroundColor: "rgba(255, 255, 255, 0.1)",
},
width: "100%",
justifyContent: "space-between",
}}
>
<Typography>Off</Typography>
{!currentSubTrack ? <CheckIcon /> : <ArrowForwardIosIcon />}
</ButtonBase>
{subtitles?.map((sub) => {
return (
<Subtitle
@ -429,21 +536,23 @@ const PublisherSubtitles = ({
};
interface PublishSubtitlesProps {
publishHandler: (subs: Subtitle[]) => void;
publishHandler: (subs: Subtitle[]) => Promise<void>;
isOpen: boolean;
setIsOpen: (val: boolean) => void;
mySubtitles: QortalGetMetadata[]
mySubtitles: QortalGetMetadata[];
}
const PublishSubtitles = ({
publishHandler,
isOpen,
setIsOpen,
mySubtitles
mySubtitles,
}: PublishSubtitlesProps) => {
const [language, setLanguage] = useState<null | string>(null);
const [subtitles, setSubtitles] = useState<Subtitle[]>([]);
const {lists} = useGlobal()
const [isPublishing, setIsPublishing] = useState(false);
const { lists } = useGlobal();
const theme = useTheme();
const onDrop = useCallback(async (acceptedFiles: File[]) => {
const newSubtitles: Subtitle[] = [];
for (const file of acceptedFiles) {
@ -495,6 +604,7 @@ const PublishSubtitles = ({
const handleClose = () => {
setIsOpen(false);
setSubtitles([]);
};
const [value, setValue] = useState(0);
@ -503,15 +613,39 @@ const PublishSubtitles = ({
setValue(newValue);
};
const onDelete = useCallback(async (sub: QortalGetMetadata)=> {
const onDelete = useCallback(async (sub: QortalGetMetadata) => {
let loadId;
try {
await lists.deleteResource([
sub
])
setIsPublishing(true);
loadId = showLoading("Deleting subtitle...");
await lists.deleteResource([sub]);
showSuccess("Deleted subtitle");
} catch (error) {
showError(error instanceof Error ? error.message : "Unable to delete");
} finally {
setIsPublishing(false);
dismissToast(loadId);
}
},[])
}, []);
const publishHandlerLocal = async (subtitles: Subtitle[]) => {
let loadId;
try {
setIsPublishing(true);
loadId = showLoading("Publishing subtitles...");
await publishHandler(subtitles);
showSuccess("Subtitles published");
setSubtitles([]);
} catch (error) {
showError(error instanceof Error ? error.message : "Unable to publish");
} finally {
dismissToast(loadId);
setIsPublishing(false);
}
};
const disableButton =
!!subtitles.find((sub) => !sub?.language) || isPublishing;
return (
<Dialog
@ -524,6 +658,10 @@ const PublishSubtitles = ({
slotProps={{
paper: {
elevation: 0,
sx: {
height: "600px",
maxHeight: "100vh",
},
},
}}
>
@ -539,7 +677,26 @@ const PublishSubtitles = ({
>
<CloseIcon />
</IconButton>
<DialogContent>
<DialogContent
sx={{
"::-webkit-scrollbar": {
width: "16px",
height: "10px",
},
"::-webkit-scrollbar-thumb": {
backgroundColor: theme.palette.primary.main,
borderRadius: "8px",
backgroundClip: "content-box",
border: "4px solid transparent",
transition: "0.3s background-color",
},
"::-webkit-scrollbar-thumb:hover": {
backgroundColor: theme.palette.primary.dark,
},
}}
>
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
@ -636,7 +793,6 @@ const PublishSubtitles = ({
alignItems: "center",
}}
>
{mySubtitles?.map((sub, i) => {
return (
<Card
@ -654,13 +810,15 @@ const PublishSubtitles = ({
)}
</DialogContent>
<DialogActions>
{value === 0 && (
<Button
onClick={() => publishHandler(subtitles)}
// disabled={disableButton}
onClick={() => publishHandlerLocal(subtitles)}
disabled={disableButton}
variant="contained"
>
Publish
</Button>
)}
</DialogActions>
</Dialog>
);
@ -672,7 +830,7 @@ interface SubProps {
currentSubtrack: null | string;
}
const Subtitle = ({ sub, onSelect, currentSubtrack }: SubProps) => {
const { resource, isLoading } = usePublish(2, "JSON", sub);
const { resource, isLoading, error } = usePublish(2, "JSON", sub);
console.log("resource", resource);
const isSelected = currentSubtrack === resource?.data?.language;
return (
@ -688,8 +846,13 @@ const Subtitle = ({ sub, onSelect, currentSubtrack }: SubProps) => {
justifyContent: "space-between",
}}
>
{isLoading && <Skeleton variant="text" sx={{ fontSize: "1.25rem", width: '100%' }} />}
{!isLoading && !error && (
<>
<Typography>{resource?.data?.language}</Typography>
{isSelected ? <CheckIcon /> : <ArrowForwardIosIcon />}
</>
)}
</ButtonBase>
);
};
@ -699,7 +862,7 @@ interface MySubtitleProps {
onDelete: (subtitle: QortalGetMetadata) => void;
}
const MySubtitle = ({ sub, onDelete }: MySubtitleProps) => {
const { resource, isLoading } = usePublish(2, "JSON", sub);
const { resource, isLoading, error } = usePublish(2, "JSON", sub);
console.log("resource", resource);
return (
<Card
@ -717,9 +880,13 @@ const MySubtitle = ({ sub, onDelete }: MySubtitleProps) => {
{resource?.data?.filename}
</Typography>
<Spacer height="10px" />
<Typography sx={{
fontSize: '1rem'
}}>{resource?.data?.language}</Typography>
<Typography
sx={{
fontSize: "1rem",
}}
>
{resource?.data?.language}
</Typography>
<Spacer height="10px" />
<Box
sx={{
@ -738,7 +905,6 @@ const MySubtitle = ({ sub, onDelete }: MySubtitleProps) => {
</Button>
</Box>
</Card>
);
};

View File

@ -13,7 +13,7 @@ import {
VolumeControl,
} from "./VideoControls";
import { Ref } from "react";
import SubtitlesIcon from '@mui/icons-material/Subtitles';
interface VideoControlsBarProps {
canPlay: boolean
isScreenSmall: boolean
@ -99,7 +99,7 @@ export const VideoControlsBar = ({subtitleBtnRef, showControls, playbackRate, in
<PlaybackRate playbackRate={playbackRate} increaseSpeed={increaseSpeed} decreaseSpeed={decreaseSpeed} />
<ObjectFitButton />
<IconButton ref={subtitleBtnRef} onClick={openSubtitleManager}>
sub
<SubtitlesIcon />
</IconButton>
<PictureInPictureButton />
<FullscreenButton toggleFullscreen={toggleFullscreen} />

View File

@ -23,14 +23,23 @@ export const VideoElement = styled("video")(({ theme }) => ({
right: 0,
left: 0,
background: "rgb(33, 33, 33)",
"&:focus": { outline: "none" },
"&:focus": {
outline: "none !important",
boxShadow: "none !important",
},
"&:focus-visible": {
outline: "none !important",
boxShadow: "none !important",
},
"&::-webkit-media-controls": {
display:"none !important"
},
"&:fullscreen": {
paddingBottom: '50px'
}
display: "none !important",
},
"&:fullscreen": {
paddingBottom: '50px',
},
}));
//1075 x 604
export const ControlsContainer = styled(Box)`
width: 100%;

View File

@ -591,6 +591,8 @@ export const VideoPlayer = ({
if (!playerRef.current && ref.current) {
playerRef.current = videojs(ref.current, options, () => {
setIsPlayerInitialized(true);
ref.current.tabIndex = -1; // Prevents focus entirely
ref.current.style.outline = 'none'; // Backup
playerRef.current?.poster("");
playerRef.current?.playbackRate(playbackRate);
playerRef.current?.volume(volume);
@ -701,7 +703,7 @@ export const VideoPlayer = ({
/>
<VideoElement
ref={videoRef}
tabIndex={0}
tabIndex={-1}
className="video-js"
src={isReady && startPlay ? resourceUrl || undefined : undefined}
poster={startPlay ? "" : poster}

View File

@ -6,3 +6,14 @@
box-sizing: border-box;
}
video:focus,
video:focus-visible,
.vjs-tech:focus,
.vjs-tech:focus-visible {
outline: none !important;
box-shadow: none !important;
}
.video-js *:focus:not(:focus-visible) {
outline: none !important;
}