mirror of
https://github.com/Qortal/q-tube.git
synced 2025-02-11 17:55:51 +00:00
Merge pull request #29 from QortalSeth/main
Publishes are stored as File instead of Base64 to Reduce Load Times
This commit is contained in:
commit
7bd0946976
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "qtube",
|
||||
"version": "0.0.0",
|
||||
"version": "2.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "qtube",
|
||||
"version": "0.0.0",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.6",
|
||||
"@emotion/styled": "^11.10.6",
|
||||
|
@ -31,7 +31,11 @@ import AddBoxIcon from "@mui/icons-material/AddBox";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import { objectToBase64, uint8ArrayToBase64 } from "../../../utils/toBase64.ts";
|
||||
import {
|
||||
objectToBase64,
|
||||
objectToFile,
|
||||
uint8ArrayToBase64,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import {
|
||||
upsertVideosBeginning,
|
||||
@ -165,14 +169,16 @@ export const EditPlaylist = () => {
|
||||
const responseDataSearchVid = await response.json();
|
||||
|
||||
if (responseDataSearchVid?.length > 0) {
|
||||
let resourceData2 = responseDataSearchVid[0];
|
||||
const resourceData2 = responseDataSearchVid[0];
|
||||
videos.push(resourceData2);
|
||||
}
|
||||
}
|
||||
}
|
||||
combinedData.videos = videos;
|
||||
setPlaylistData(combinedData);
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@ -263,13 +269,13 @@ export const EditPlaylist = () => {
|
||||
if (!descriptionVid) throw new Error("cannot find video code");
|
||||
|
||||
// Split the string by ';'
|
||||
let parts = descriptionVid.split(";");
|
||||
const parts = descriptionVid.split(";");
|
||||
|
||||
// Initialize a variable to hold the code value
|
||||
let codeValue = "";
|
||||
|
||||
// Loop through the parts to find the one that starts with 'code:'
|
||||
for (let part of parts) {
|
||||
for (const part of parts) {
|
||||
if (part.startsWith("code:")) {
|
||||
codeValue = part.split(":")[1];
|
||||
break;
|
||||
@ -309,11 +315,10 @@ export const EditPlaylist = () => {
|
||||
.map(item => `c:${item.code};`)
|
||||
.slice(0, 10)
|
||||
.join("");
|
||||
let metadescription =
|
||||
const metadescription =
|
||||
`**category:${category};subcategory:${subcategory};${codes}**` +
|
||||
stringDescription.slice(0, 120);
|
||||
|
||||
const crowdfundObjectToBase64 = await objectToBase64(playlistObject);
|
||||
// Description is obtained from raw data
|
||||
|
||||
let identifier = editVideoProperties?.id;
|
||||
@ -333,7 +338,7 @@ export const EditPlaylist = () => {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: username,
|
||||
service: "PLAYLIST",
|
||||
data64: crowdfundObjectToBase64,
|
||||
file: objectToFile(playlistObject),
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
identifier: identifier,
|
||||
|
@ -35,7 +35,11 @@ import AddBoxIcon from "@mui/icons-material/AddBox";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import { objectToBase64, uint8ArrayToBase64 } from "../../../utils/toBase64.ts";
|
||||
import {
|
||||
objectToBase64,
|
||||
objectToFile,
|
||||
uint8ArrayToBase64,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import {
|
||||
upsertVideosBeginning,
|
||||
@ -53,7 +57,11 @@ import { extractTextFromHTML } from "../../common/TextEditor/utils.ts";
|
||||
import { toBase64 } from "../PublishVideo/PublishVideo.tsx";
|
||||
import { FrameExtractor } from "../../common/FrameExtractor/FrameExtractor.tsx";
|
||||
import { QTUBE_VIDEO_BASE } from "../../../constants/Identifiers.ts";
|
||||
import { titleFormatter } from "../../../constants/Misc.ts";
|
||||
import {
|
||||
maxSize,
|
||||
titleFormatter,
|
||||
videoMaxSize,
|
||||
} from "../../../constants/Misc.ts";
|
||||
|
||||
const uid = new ShortUniqueId();
|
||||
const shortuid = new ShortUniqueId({ length: 5 });
|
||||
@ -103,7 +111,7 @@ export const EditVideo = () => {
|
||||
"video/*": [],
|
||||
},
|
||||
maxFiles: 1,
|
||||
maxSize: 419430400, // 400 MB in bytes
|
||||
maxSize,
|
||||
onDrop: (acceptedFiles, rejectedFiles) => {
|
||||
const firstFile = acceptedFiles[0];
|
||||
|
||||
@ -114,7 +122,7 @@ export const EditVideo = () => {
|
||||
rejectedFiles.forEach(({ file, errors }) => {
|
||||
errors.forEach(error => {
|
||||
if (error.code === "file-too-large") {
|
||||
errorString = "File must be under 400mb";
|
||||
errorString = `File must be under ${videoMaxSize}MB`;
|
||||
}
|
||||
console.log(`Error with file ${file.name}: ${error.message}`);
|
||||
});
|
||||
@ -248,7 +256,7 @@ export const EditVideo = () => {
|
||||
);
|
||||
return;
|
||||
}
|
||||
let listOfPublishes = [];
|
||||
const listOfPublishes = [];
|
||||
const category = selectedCategoryVideos.id;
|
||||
const subcategory = selectedSubCategoryVideos?.id || "";
|
||||
|
||||
@ -259,14 +267,14 @@ export const EditVideo = () => {
|
||||
fileExtension = fileExtensionSplit?.pop() || "mp4";
|
||||
}
|
||||
|
||||
let filename = title.slice(0, 15);
|
||||
const filename = title.slice(0, 15);
|
||||
// Step 1: Replace all white spaces with underscores
|
||||
|
||||
// Replace all forms of whitespace (including non-standard ones) with underscores
|
||||
let stringWithUnderscores = filename.replace(/[\s\uFEFF\xA0]+/g, "_");
|
||||
const stringWithUnderscores = filename.replace(/[\s\uFEFF\xA0]+/g, "_");
|
||||
|
||||
// Remove all non-alphanumeric characters (except underscores)
|
||||
let alphanumericString = stringWithUnderscores.replace(
|
||||
const alphanumericString = stringWithUnderscores.replace(
|
||||
/[^a-zA-Z0-9_]/g,
|
||||
""
|
||||
);
|
||||
@ -287,17 +295,16 @@ export const EditVideo = () => {
|
||||
filename: `${alphanumericString.trim()}.${fileExtension}`,
|
||||
};
|
||||
|
||||
let metadescription =
|
||||
const metadescription =
|
||||
`**category:${category};subcategory:${subcategory};code:${editVideoProperties.code}**` +
|
||||
description.slice(0, 150);
|
||||
|
||||
const crowdfundObjectToBase64 = await objectToBase64(videoObject);
|
||||
// Description is obtained from raw data
|
||||
const requestBodyJson: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: username,
|
||||
service: "DOCUMENT",
|
||||
data64: crowdfundObjectToBase64,
|
||||
file: objectToFile(videoObject),
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
identifier: editVideoProperties.id,
|
||||
@ -318,7 +325,6 @@ export const EditVideo = () => {
|
||||
tag1: QTUBE_VIDEO_BASE,
|
||||
filename: `${alphanumericString.trim()}.${fileExtension}`,
|
||||
};
|
||||
|
||||
listOfPublishes.push(requestBodyVideo);
|
||||
}
|
||||
|
||||
@ -377,7 +383,7 @@ export const EditVideo = () => {
|
||||
|
||||
const onFramesExtracted = async imgs => {
|
||||
try {
|
||||
let imagesExtracts = [];
|
||||
const imagesExtracts = [];
|
||||
|
||||
for (const img of imgs) {
|
||||
try {
|
||||
@ -395,7 +401,9 @@ export const EditVideo = () => {
|
||||
compressedFile = file;
|
||||
resolve();
|
||||
},
|
||||
error(err) {},
|
||||
error(error) {
|
||||
console.log(error);
|
||||
},
|
||||
});
|
||||
});
|
||||
if (!compressedFile) continue;
|
||||
@ -407,7 +415,9 @@ export const EditVideo = () => {
|
||||
}
|
||||
|
||||
setImageExtracts(imagesExtracts);
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -78,7 +78,7 @@ export const MultiplePublish = ({
|
||||
);
|
||||
|
||||
const retry = () => {
|
||||
let newlistOfMultiplePublishes: any[] = [];
|
||||
const newlistOfMultiplePublishes: any[] = [];
|
||||
listOfUnsuccessfulPublishes?.forEach(item => {
|
||||
const findPub = publishes?.resources.find(
|
||||
(res: any) => res?.identifier === item.identifier
|
||||
@ -125,6 +125,7 @@ export const MultiplePublish = ({
|
||||
);
|
||||
return (
|
||||
<Box
|
||||
key={publish?.identifier}
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
|
@ -38,7 +38,7 @@ import { useDropzone } from "react-dropzone";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import { objectToBase64, uint8ArrayToBase64 } from "../../../utils/toBase64.ts";
|
||||
import { objectToBase64, objectToFile, uint8ArrayToBase64 } from "../../../utils/PublishFormatter.ts";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import {
|
||||
upsertVideosBeginning,
|
||||
@ -65,7 +65,7 @@ import {
|
||||
QTUBE_PLAYLIST_BASE,
|
||||
QTUBE_VIDEO_BASE,
|
||||
} from "../../../constants/Identifiers.ts";
|
||||
import { titleFormatter } from "../../../constants/Misc.ts";
|
||||
import { maxSize, titleFormatter, videoMaxSize } from "../../../constants/Misc.ts";
|
||||
import { getFileName } from "../../../utils/stringFunctions.ts";
|
||||
|
||||
export const toBase64 = (file: File): Promise<string | ArrayBuffer | null> =>
|
||||
@ -137,11 +137,13 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
const [isCheckDescriptionIsTitle, setIsCheckDescriptionIsTitle] =
|
||||
useState(false);
|
||||
const [imageExtracts, setImageExtracts] = useState<any>({});
|
||||
|
||||
|
||||
const { getRootProps, getInputProps } = useDropzone({
|
||||
accept: {
|
||||
"video/*": [],
|
||||
},
|
||||
maxSize: 419430400, // 400 MB in bytes
|
||||
maxSize,
|
||||
onDrop: (acceptedFiles, rejectedFiles) => {
|
||||
const formatArray = acceptedFiles.map(item => {
|
||||
let filteredTitle = "";
|
||||
@ -164,7 +166,7 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
rejectedFiles.forEach(({ file, errors }) => {
|
||||
errors.forEach(error => {
|
||||
if (error.code === "file-too-large") {
|
||||
errorString = "File must be under 400mb";
|
||||
errorString = `File must be under ${videoMaxSize}MB`;
|
||||
}
|
||||
console.log(`Error with file ${file.name}: ${error.message}`);
|
||||
});
|
||||
@ -180,10 +182,10 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (editContent) {
|
||||
}
|
||||
}, [editContent]);
|
||||
// useEffect(() => {
|
||||
// if (editContent) {
|
||||
// }
|
||||
// }, [editContent]);
|
||||
|
||||
const onClose = () => {
|
||||
setIsOpen(false);
|
||||
@ -238,7 +240,7 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
return;
|
||||
}
|
||||
|
||||
let listOfPublishes = [];
|
||||
const listOfPublishes = [];
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const publish = files[i];
|
||||
@ -274,18 +276,17 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
fileExtension = fileExtensionSplit?.pop() || "mp4";
|
||||
}
|
||||
|
||||
let filename = title.slice(0, 15);
|
||||
const filename = title.slice(0, 15);
|
||||
// Step 1: Replace all white spaces with underscores
|
||||
|
||||
// Replace all forms of whitespace (including non-standard ones) with underscores
|
||||
let stringWithUnderscores = filename.replace(/[\s\uFEFF\xA0]+/g, "_");
|
||||
const stringWithUnderscores = filename.replace(/[\s\uFEFF\xA0]+/g, "_");
|
||||
|
||||
// Remove all non-alphanumeric characters (except underscores)
|
||||
let alphanumericString = stringWithUnderscores.replace(
|
||||
const alphanumericString = stringWithUnderscores.replace(
|
||||
/[^a-zA-Z0-9_]/g,
|
||||
""
|
||||
);
|
||||
|
||||
const videoObject: any = {
|
||||
title,
|
||||
version: 1,
|
||||
@ -306,17 +307,16 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
filename: `${alphanumericString.trim()}.${fileExtension}`,
|
||||
};
|
||||
|
||||
let metadescription =
|
||||
const metadescription =
|
||||
`**category:${category};subcategory:${subcategory};code:${code}**` +
|
||||
fullDescription.slice(0, 150);
|
||||
|
||||
const crowdfundObjectToBase64 = await objectToBase64(videoObject);
|
||||
// Description is obtained from raw data
|
||||
const requestBodyJson: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "DOCUMENT",
|
||||
data64: crowdfundObjectToBase64,
|
||||
file: objectToFile(videoObject),
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
identifier: identifier + "_metadata",
|
||||
@ -392,17 +392,17 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
.slice(0, 10)
|
||||
.join("");
|
||||
|
||||
let metadescription =
|
||||
const metadescription =
|
||||
`**category:${category};subcategory:${subcategory};${codes}**` +
|
||||
stringDescription.slice(0, 120);
|
||||
|
||||
const crowdfundObjectToBase64 = await objectToBase64(playlistObject);
|
||||
|
||||
// Description is obtained from raw data
|
||||
const requestBodyJson: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "PLAYLIST",
|
||||
data64: crowdfundObjectToBase64,
|
||||
file: objectToFile(playlistObject),
|
||||
title: title.slice(0, 50),
|
||||
description: metadescription,
|
||||
identifier: identifier + "_metadata",
|
||||
@ -447,17 +447,17 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
.slice(0, 10)
|
||||
.join("");
|
||||
|
||||
let metadescription =
|
||||
const metadescription =
|
||||
`**category:${playlistObject.category};subcategory:${playlistObject.subcategory};${codes}**` +
|
||||
playlistObject.description.slice(0, 120);
|
||||
|
||||
const crowdfundObjectToBase64 = await objectToBase64(playlistObject);
|
||||
|
||||
// Description is obtained from raw data
|
||||
const requestBodyJson: any = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "PLAYLIST",
|
||||
data64: crowdfundObjectToBase64,
|
||||
file: objectToFile( playlistObject),
|
||||
title: playlistObject.title.slice(0, 50),
|
||||
description: metadescription,
|
||||
identifier: selectExistingPlaylist.identifier,
|
||||
@ -480,24 +480,24 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
let notificationObj: any = null;
|
||||
if (typeof error === "string") {
|
||||
notificationObj = {
|
||||
msg: error || "Failed to publish crowdfund",
|
||||
msg: error || "Failed to publish video",
|
||||
alertType: "error",
|
||||
};
|
||||
} else if (typeof error?.error === "string") {
|
||||
notificationObj = {
|
||||
msg: error?.error || "Failed to publish crowdfund",
|
||||
msg: error?.error || "Failed to publish video",
|
||||
alertType: "error",
|
||||
};
|
||||
} else {
|
||||
notificationObj = {
|
||||
msg: error?.message || "Failed to publish crowdfund",
|
||||
msg: error?.message || "Failed to publish video",
|
||||
alertType: "error",
|
||||
};
|
||||
}
|
||||
if (!notificationObj) return;
|
||||
dispatch(setNotification(notificationObj));
|
||||
|
||||
throw new Error("Failed to publish crowdfund");
|
||||
throw new Error("Failed to publish video");
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,7 +578,7 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
|
||||
const onFramesExtracted = async (imgs, index) => {
|
||||
try {
|
||||
let imagesExtracts = [];
|
||||
const imagesExtracts = [];
|
||||
|
||||
for (const img of imgs) {
|
||||
try {
|
||||
@ -596,7 +596,7 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
compressedFile = file;
|
||||
resolve();
|
||||
},
|
||||
error(err) {},
|
||||
error(error) {console.log(error)},
|
||||
});
|
||||
});
|
||||
if (!compressedFile) continue;
|
||||
@ -613,7 +613,7 @@ export const PublishVideo = ({ editId, editContent }: NewCrowdfundProps) => {
|
||||
[index]: imagesExtracts,
|
||||
};
|
||||
});
|
||||
} catch (error) {}
|
||||
} catch (error) {console.log(error)}
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -4,7 +4,10 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { setNotification } from "../../../state/features/notificationsSlice";
|
||||
import { toBase64 } from "../../../utils/toBase64";
|
||||
import {
|
||||
publishFormatter,
|
||||
stringToFile,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import localforage from "localforage";
|
||||
import {
|
||||
CommentInput,
|
||||
@ -30,11 +33,13 @@ export interface Item {
|
||||
|
||||
export async function addItem(item: Item): Promise<void> {
|
||||
// Get all items
|
||||
let notificationComments: Item[] =
|
||||
const notificationComments: Item[] =
|
||||
(await notification.getItem("comments")) || [];
|
||||
|
||||
// Find the item with the same id, if it exists
|
||||
let existingItemIndex = notificationComments.findIndex(i => i.id === item.id);
|
||||
const existingItemIndex = notificationComments.findIndex(
|
||||
i => i.id === item.id
|
||||
);
|
||||
|
||||
if (existingItemIndex !== -1) {
|
||||
// If the item exists, update its date
|
||||
@ -55,10 +60,10 @@ export async function addItem(item: Item): Promise<void> {
|
||||
}
|
||||
export async function updateItemDate(item: any): Promise<void> {
|
||||
// Get all items
|
||||
let notificationComments: Item[] =
|
||||
const notificationComments: Item[] =
|
||||
(await notification.getItem("comments")) || [];
|
||||
|
||||
let notificationCreatorComment: any =
|
||||
const notificationCreatorComment: any =
|
||||
(await notification.getItem("post-comments")) || {};
|
||||
const findPostId = notificationCreatorComment[item.postId];
|
||||
if (findPostId) {
|
||||
@ -121,13 +126,10 @@ export const CommentEditor = ({
|
||||
identifier: string,
|
||||
idForNotification?: string
|
||||
) => {
|
||||
let address;
|
||||
let name;
|
||||
const address = user?.address;
|
||||
const name = user?.name || "";
|
||||
let errorMsg = "";
|
||||
|
||||
address = user?.address;
|
||||
name = user?.name || "";
|
||||
|
||||
if (!address) {
|
||||
errorMsg = "Cannot post: your address isn't available";
|
||||
}
|
||||
@ -150,12 +152,11 @@ export const CommentEditor = ({
|
||||
}
|
||||
|
||||
try {
|
||||
const base64 = utf8ToBase64(value);
|
||||
const resourceResponse = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "BLOG_COMMENT",
|
||||
data64: base64,
|
||||
file: stringToFile(value),
|
||||
identifier: identifier,
|
||||
});
|
||||
dispatch(
|
||||
|
@ -14,7 +14,7 @@ export const getCurrentLikeType = async (
|
||||
});
|
||||
return response?.likeType;
|
||||
} catch (e) {
|
||||
console.log("liketype error: ", e);
|
||||
// console.log("liketype error: ", e);
|
||||
return NEUTRAL;
|
||||
}
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ import { Box, Tooltip } from "@mui/material";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { objectToBase64 } from "../../../utils/toBase64.ts";
|
||||
import { objectToBase64 } from "../../../utils/PublishFormatter.ts";
|
||||
import { RootState } from "../../../state/store.ts";
|
||||
import { FOR, FOR_LIKE, LIKE_BASE } from "../../../constants/Identifiers.ts";
|
||||
import {
|
||||
|
@ -21,7 +21,10 @@ import { MultiplePublish } from "../../Publish/MultiplePublish/MultiplePublishAl
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { setNotification } from "../../../state/features/notificationsSlice.ts";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { objectToBase64 } from "../../../utils/toBase64.ts";
|
||||
import {
|
||||
objectToBase64,
|
||||
objectToFile,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import { minPriceSuperlike } from "../../../constants/Misc.ts";
|
||||
import { CommentInput } from "../Comments/Comments-styles.tsx";
|
||||
import {
|
||||
@ -55,9 +58,7 @@ export const SuperLike = ({
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
|
||||
const [superlikeDonationAmount, setSuperlikeDonationAmount] =
|
||||
useState<number>(10);
|
||||
const [qortalDevDonationAmount, setQortalDevDonationAmount] =
|
||||
useState<number>(0);
|
||||
useState<number>(minPriceSuperlike);
|
||||
const [currentBalance, setCurrentBalance] = useState<string>("");
|
||||
|
||||
const [comment, setComment] = useState<string>("");
|
||||
@ -82,15 +83,12 @@ export const SuperLike = ({
|
||||
if (!name) throw new Error("Could not retrieve content creator's name");
|
||||
const estimatedTransactionFees = 0.1;
|
||||
const donationExceedsBalance =
|
||||
superlikeDonationAmount +
|
||||
qortalDevDonationAmount +
|
||||
estimatedTransactionFees >=
|
||||
+currentBalance;
|
||||
superlikeDonationAmount + estimatedTransactionFees >= +currentBalance;
|
||||
if (donationExceedsBalance) {
|
||||
throw new Error("Total donations exceeds current balance");
|
||||
}
|
||||
|
||||
let resName = await qortalRequest({
|
||||
const resName = await qortalRequest({
|
||||
action: "GET_NAME_DATA",
|
||||
name: name,
|
||||
});
|
||||
@ -106,10 +104,10 @@ export const SuperLike = ({
|
||||
superlikeDonationAmount < minPriceSuperlike
|
||||
)
|
||||
throw new Error(
|
||||
`The amount needs to be at least ${minPriceSuperlike} QORT`
|
||||
`The amount is ${superlikeDonationAmount}, but it needs to be at least ${minPriceSuperlike} QORT`
|
||||
);
|
||||
|
||||
let listOfPublishes = [];
|
||||
const listOfPublishes = [];
|
||||
|
||||
const res = await qortalRequest({
|
||||
action: "SEND_COIN",
|
||||
@ -118,24 +116,7 @@ export const SuperLike = ({
|
||||
amount: superlikeDonationAmount,
|
||||
});
|
||||
|
||||
const devDonation = qortalDevDonationAmount > 0;
|
||||
if (devDonation) {
|
||||
const devFundName = "DevFund";
|
||||
|
||||
let devFundNameData = await qortalRequest({
|
||||
action: "GET_NAME_DATA",
|
||||
name: devFundName,
|
||||
});
|
||||
|
||||
const devFundAddress = devFundNameData.owner;
|
||||
const resDevFund = await qortalRequest({
|
||||
action: "SEND_COIN",
|
||||
coin: "QORT",
|
||||
destinationAddress: devFundAddress,
|
||||
amount: qortalDevDonationAmount,
|
||||
});
|
||||
}
|
||||
let metadescription = `**sig:${
|
||||
const metadescription = `**sig:${
|
||||
res.signature
|
||||
};${FOR}:${name}_${FOR_SUPER_LIKE};nm:${name.slice(
|
||||
0,
|
||||
@ -148,7 +129,7 @@ export const SuperLike = ({
|
||||
39
|
||||
)}_${id}`;
|
||||
|
||||
const superLikeToBase64 = await objectToBase64({
|
||||
const superLikeToFile = objectToFile({
|
||||
comment,
|
||||
transactionReference: res.signature,
|
||||
notificationInformation: {
|
||||
@ -166,7 +147,7 @@ export const SuperLike = ({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: username,
|
||||
service: "BLOG_COMMENT",
|
||||
data64: superLikeToBase64,
|
||||
file: superLikeToFile,
|
||||
title: "",
|
||||
description: metadescription,
|
||||
identifier: identifierSuperLike,
|
||||
@ -187,9 +168,9 @@ export const SuperLike = ({
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg:
|
||||
error ||
|
||||
error?.error ||
|
||||
error?.message ||
|
||||
error ||
|
||||
"Failed to publish Super Like",
|
||||
alertType: "error",
|
||||
})
|
||||
@ -339,36 +320,6 @@ export const SuperLike = ({
|
||||
InputLabelProps={{ style: { fontSize: "18px" } }}
|
||||
onChange={e => setComment(e.target.value)}
|
||||
/>
|
||||
<Spacer height="50px" />
|
||||
<InputLabel
|
||||
htmlFor="standard-adornment-amount"
|
||||
style={{ paddingBottom: "10px" }}
|
||||
>
|
||||
Would you like to donate to Qortal Development?
|
||||
</InputLabel>
|
||||
<BoundedNumericTextField
|
||||
minValue={0}
|
||||
initialValue={""}
|
||||
maxValue={numberToInt(+currentBalance)}
|
||||
allowDecimals={false}
|
||||
value={superlikeDonationAmount}
|
||||
afterChange={(e: string) => setQortalDevDonationAmount(+e)}
|
||||
InputProps={{
|
||||
style: { fontSize: 30, width: textFieldWidth },
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<img
|
||||
style={{
|
||||
height: "40px",
|
||||
width: "40px",
|
||||
}}
|
||||
src={qortImg}
|
||||
alt={"Qort Icon"}
|
||||
/>
|
||||
</InputAdornment>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<CrowdfundActionButtonRow>
|
||||
|
@ -4,7 +4,12 @@ import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../../../state/store";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { setNotification } from "../../../state/features/notificationsSlice";
|
||||
import { objectToBase64, toBase64 } from "../../../utils/toBase64";
|
||||
import {
|
||||
objectToBase64,
|
||||
objectToFile,
|
||||
publishFormatter,
|
||||
stringToFile,
|
||||
} from "../../../utils/PublishFormatter.ts";
|
||||
import localforage from "localforage";
|
||||
import {
|
||||
CommentInput,
|
||||
@ -30,11 +35,13 @@ export interface Item {
|
||||
|
||||
export async function addItem(item: Item): Promise<void> {
|
||||
// Get all items
|
||||
let notificationComments: Item[] =
|
||||
const notificationComments: Item[] =
|
||||
(await notification.getItem("comments")) || [];
|
||||
|
||||
// Find the item with the same id, if it exists
|
||||
let existingItemIndex = notificationComments.findIndex(i => i.id === item.id);
|
||||
const existingItemIndex = notificationComments.findIndex(
|
||||
i => i.id === item.id
|
||||
);
|
||||
|
||||
if (existingItemIndex !== -1) {
|
||||
// If the item exists, update its date
|
||||
@ -55,10 +62,10 @@ export async function addItem(item: Item): Promise<void> {
|
||||
}
|
||||
export async function updateItemDate(item: any): Promise<void> {
|
||||
// Get all items
|
||||
let notificationComments: Item[] =
|
||||
const notificationComments: Item[] =
|
||||
(await notification.getItem("comments")) || [];
|
||||
|
||||
let notificationCreatorComment: any =
|
||||
const notificationCreatorComment: any =
|
||||
(await notification.getItem("post-comments")) || {};
|
||||
const findPostId = notificationCreatorComment[item.postId];
|
||||
if (findPostId) {
|
||||
@ -127,13 +134,10 @@ export const CommentEditor = ({
|
||||
identifier: string,
|
||||
idForNotification?: string
|
||||
) => {
|
||||
let address;
|
||||
let name;
|
||||
const address = user?.address;
|
||||
const name = user?.name || "";
|
||||
let errorMsg = "";
|
||||
|
||||
address = user?.address;
|
||||
name = user?.name || "";
|
||||
|
||||
if (!address) {
|
||||
errorMsg = "Cannot post: your address isn't available";
|
||||
}
|
||||
@ -156,7 +160,7 @@ export const CommentEditor = ({
|
||||
}
|
||||
|
||||
try {
|
||||
let data64 = null;
|
||||
let dataFile = null;
|
||||
let description = "";
|
||||
let tag1 = "";
|
||||
let superObj = {};
|
||||
@ -177,17 +181,18 @@ export const CommentEditor = ({
|
||||
notificationInformation: comment.notificationInformation,
|
||||
about: comment.about,
|
||||
};
|
||||
const superLikeToBase64 = await objectToBase64(superObj);
|
||||
data64 = superLikeToBase64;
|
||||
const superLikeToFile = await objectToFile(superObj);
|
||||
dataFile = superLikeToFile;
|
||||
}
|
||||
if (isSuperLike && !data64) throw new Error("unable to edit Super like");
|
||||
if (isSuperLike && !dataFile)
|
||||
throw new Error("unable to edit Super like");
|
||||
|
||||
const base64 = utf8ToBase64(value);
|
||||
const stringFile = stringToFile(value);
|
||||
const resourceResponse = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "BLOG_COMMENT",
|
||||
data64: isSuperLike ? data64 : base64,
|
||||
file: isSuperLike ? dataFile : stringFile,
|
||||
identifier: identifier,
|
||||
description,
|
||||
tag1,
|
||||
@ -248,7 +253,7 @@ export const CommentEditor = ({
|
||||
|
||||
let identifier = `${COMMENT_BASE}${postId.slice(-12)}_base_${id}`;
|
||||
let idForNotification = identifier;
|
||||
let service = "BLOG_COMMENT";
|
||||
const service = "BLOG_COMMENT";
|
||||
if (isReply && commentId) {
|
||||
const removeBaseCommentId = commentId;
|
||||
removeBaseCommentId.replace("_base_", "");
|
||||
|
@ -1,3 +1,6 @@
|
||||
export const minPriceSuperlike = 1;
|
||||
export const titleFormatter = /[^a-zA-Z0-9\s-_!?()&'",.;:|—~@#$%^*+=<>]/g;
|
||||
export const titleFormatterOnSave = /[^a-zA-Z0-9\s-_!()&',.;—~@#$%^+=]/g;
|
||||
|
||||
export const videoMaxSize = 400; // Size in Megabytes (decimal)
|
||||
export const maxSize = videoMaxSize *1024*1024
|
@ -7,7 +7,7 @@ import {
|
||||
upsertVideos,
|
||||
upsertVideosBeginning,
|
||||
Video,
|
||||
upsertFilteredVideos,
|
||||
upsertFilteredVideos, removeFromHashMap,
|
||||
} from "../state/features/videoSlice";
|
||||
import {
|
||||
setIsLoadingGlobal,
|
||||
@ -72,7 +72,7 @@ export const useFetchVideos = () => {
|
||||
|
||||
const getAvatar = React.useCallback(async (author: string) => {
|
||||
try {
|
||||
let url = await qortalRequest({
|
||||
const url = await qortalRequest({
|
||||
action: "GET_QDN_RESOURCE_URL",
|
||||
name: author,
|
||||
service: "THUMBNAIL",
|
||||
@ -85,14 +85,14 @@ export const useFetchVideos = () => {
|
||||
url,
|
||||
})
|
||||
);
|
||||
} catch (error) {}
|
||||
} catch (error) {console.log(error)}
|
||||
}, []);
|
||||
|
||||
const getVideo = async (
|
||||
user: string,
|
||||
videoId: string,
|
||||
content: any,
|
||||
retries: number = 0
|
||||
retries = 0
|
||||
) => {
|
||||
try {
|
||||
const res = await fetchAndEvaluateVideos({
|
||||
@ -100,8 +100,11 @@ export const useFetchVideos = () => {
|
||||
videoId,
|
||||
content,
|
||||
});
|
||||
|
||||
dispatch(addToHashMap(res));
|
||||
if (res?.isValid) {
|
||||
dispatch(addToHashMap(res));
|
||||
} else {
|
||||
dispatch(removeFromHashMap(videoId));
|
||||
}
|
||||
} catch (error) {
|
||||
retries = retries + 1;
|
||||
if (retries < 2) {
|
||||
@ -183,7 +186,7 @@ export const useFetchVideos = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error) {console.log(error)
|
||||
} finally {
|
||||
dispatch(setIsLoadingGlobal(false));
|
||||
}
|
||||
@ -311,7 +314,6 @@ export const useFetchVideos = () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log({ error });
|
||||
} finally {
|
||||
}
|
||||
},
|
||||
[videos, hashMapVideos]
|
||||
@ -370,8 +372,7 @@ export const useFetchVideos = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} finally {
|
||||
} catch (error) {console.log(error)
|
||||
}
|
||||
},
|
||||
[filteredVideos, hashMapVideos]
|
||||
@ -411,12 +412,12 @@ export const useFetchVideos = () => {
|
||||
const newArray = responseData.slice(0, findVideo);
|
||||
dispatch(setCountNewVideos(newArray.length));
|
||||
return;
|
||||
} catch (error) {}
|
||||
} catch (error) {console.log(error)}
|
||||
}, [videos]);
|
||||
|
||||
const getVideosCount = React.useCallback(async () => {
|
||||
try {
|
||||
let url = `/arbitrary/resources/search?mode=ALL&includemetadata=false&limit=0&service=DOCUMENT&identifier=${QTUBE_VIDEO_BASE}`;
|
||||
const url = `/arbitrary/resources/search?mode=ALL&includemetadata=false&limit=0&service=DOCUMENT&identifier=${QTUBE_VIDEO_BASE}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
@ -436,7 +437,6 @@ export const useFetchVideos = () => {
|
||||
dispatch(setVideosPerNamePublished(videosPerNamePublished));
|
||||
} catch (error) {
|
||||
console.log({ error });
|
||||
} finally {
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
@ -65,10 +65,10 @@ import { LikeAndDislike } from "../../../components/common/ContentButtons/LikeAn
|
||||
|
||||
export function isTimestampWithinRange(resTimestamp, resCreated) {
|
||||
// Calculate the absolute difference in milliseconds
|
||||
var difference = Math.abs(resTimestamp - resCreated);
|
||||
const difference = Math.abs(resTimestamp - resCreated);
|
||||
|
||||
// 2 minutes in milliseconds
|
||||
var twoMinutesInMilliseconds = 3 * 60 * 1000;
|
||||
const twoMinutesInMilliseconds = 3 * 60 * 1000;
|
||||
|
||||
// Check if the difference is within 2 minutes
|
||||
return difference <= twoMinutesInMilliseconds;
|
||||
@ -282,6 +282,7 @@ export const VideoContent = () => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
dispatch(setIsLoadingGlobal(false));
|
||||
}
|
||||
@ -356,7 +357,9 @@ export const VideoContent = () => {
|
||||
},
|
||||
];
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,15 @@
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import { Avatar, Box, Tooltip, useTheme } from "@mui/material";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG.tsx";
|
||||
import ResponsiveImage from "../../components/ResponsiveImage.tsx";
|
||||
import { blockUser, setEditPlaylist, setEditVideo, Video } from "../../state/features/videoSlice.ts";
|
||||
import { RootState } from "../../state/store.ts";
|
||||
import { formatDate } from "../../utils/time.ts";
|
||||
import { VideoCardImageContainer } from "./VideoCardImageContainer.tsx";
|
||||
import {
|
||||
BlockIconContainer,
|
||||
BottomParent,
|
||||
@ -10,23 +22,7 @@ import {
|
||||
VideoCardTitle,
|
||||
VideoUploadDate,
|
||||
} from "./VideoList-styles.tsx";
|
||||
import { Avatar, Box, Tooltip, useTheme } from "@mui/material";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import {
|
||||
blockUser,
|
||||
setEditPlaylist,
|
||||
setEditVideo,
|
||||
} from "../../state/features/videoSlice.ts";
|
||||
import BlockIcon from "@mui/icons-material/Block";
|
||||
import ResponsiveImage from "../../components/ResponsiveImage.tsx";
|
||||
import { formatDate } from "../../utils/time.ts";
|
||||
import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG.tsx";
|
||||
import { VideoCardImageContainer } from "./VideoCardImageContainer.tsx";
|
||||
import React, { useState } from "react";
|
||||
import { Video } from "../../state/features/videoSlice.ts";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { RootState } from "../../state/store.ts";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
interface VideoListProps {
|
||||
videos: Video[];
|
||||
}
|
||||
@ -59,12 +55,16 @@ export const VideoList = ({ videos }: VideoListProps) => {
|
||||
if (response === true) {
|
||||
dispatch(blockUser(user));
|
||||
}
|
||||
} catch (error) {}
|
||||
} catch (error) {console.log(error)}
|
||||
};
|
||||
|
||||
const filteredVideos = useMemo(() => {
|
||||
return videos.filter((video: Video) => hashMapVideos[`${video.id}-${video.user}`]?.isValid);
|
||||
}, [videos, hashMapVideos]);
|
||||
|
||||
return (
|
||||
<VideoCardContainer>
|
||||
{videos.map((video: any) => {
|
||||
{filteredVideos.map((video: any) => {
|
||||
const fullId = video ? `${video.id}-${video.user}` : undefined;
|
||||
const existingVideo = hashMapVideos[fullId];
|
||||
let hasHash = false;
|
||||
|
@ -1,90 +1,107 @@
|
||||
export const toBase64 = (file: File): Promise<string | ArrayBuffer | null> =>
|
||||
export const publishFormatter = (
|
||||
file: File
|
||||
): Promise<string | ArrayBuffer | null> =>
|
||||
new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file)
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
|
||||
reader.onload = () => {
|
||||
const result = reader.result
|
||||
reader.onload = null // remove onload handler
|
||||
reader.onerror = null // remove onerror handler
|
||||
resolve(result)
|
||||
}
|
||||
const result = reader.result;
|
||||
reader.onload = null; // remove onload handler
|
||||
reader.onerror = null; // remove onerror handler
|
||||
resolve(result);
|
||||
};
|
||||
|
||||
reader.onerror = (error) => {
|
||||
reader.onload = null // remove onload handler
|
||||
reader.onerror = null // remove onerror handler
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
reader.onerror = error => {
|
||||
reader.onload = null; // remove onload handler
|
||||
reader.onerror = null; // remove onerror handler
|
||||
reject(error);
|
||||
};
|
||||
});
|
||||
|
||||
export function objectToBase64(obj: any) {
|
||||
// Step 1: Convert the object to a JSON string
|
||||
const jsonString = JSON.stringify(obj)
|
||||
const jsonString = JSON.stringify(obj);
|
||||
|
||||
// Step 2: Create a Blob from the JSON string
|
||||
const blob = new Blob([jsonString], { type: 'application/json' })
|
||||
const blob = new Blob([jsonString], { type: "application/json" });
|
||||
|
||||
// Step 3: Create a FileReader to read the Blob as a base64-encoded string
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
if (typeof reader.result === 'string') {
|
||||
if (typeof reader.result === "string") {
|
||||
// Remove 'data:application/json;base64,' prefix
|
||||
const base64 = reader.result.replace(
|
||||
'data:application/json;base64,',
|
||||
''
|
||||
)
|
||||
resolve(base64)
|
||||
"data:application/json;base64,",
|
||||
""
|
||||
);
|
||||
resolve(base64);
|
||||
} else {
|
||||
reject(new Error('Failed to read the Blob as a base64-encoded string'))
|
||||
reject(new Error("Failed to read the Blob as a base64-encoded string"));
|
||||
}
|
||||
}
|
||||
};
|
||||
reader.onerror = () => {
|
||||
reject(reader.error)
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
})
|
||||
reject(reader.error);
|
||||
};
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
export const stringToFile = (text: string) => {
|
||||
return new File([text], "", {
|
||||
type: "text/plain",
|
||||
});
|
||||
};
|
||||
export const objectToFile = (obj: object) => {
|
||||
// Step 1: Convert the object to a JSON string
|
||||
const jsonString = JSON.stringify(obj);
|
||||
|
||||
const fileType = { type: "application/json" };
|
||||
// Step 2: Create a Blob from the JSON string
|
||||
const blob = new Blob([jsonString], fileType);
|
||||
return new File([blob], ``, fileType);
|
||||
};
|
||||
|
||||
export function objectToUint8Array(obj: any) {
|
||||
// Convert the object to a JSON string
|
||||
const jsonString = JSON.stringify(obj)
|
||||
const jsonString = JSON.stringify(obj);
|
||||
|
||||
// Encode the JSON string as a byte array using TextEncoder
|
||||
const encoder = new TextEncoder()
|
||||
const byteArray = encoder.encode(jsonString)
|
||||
const encoder = new TextEncoder();
|
||||
const byteArray = encoder.encode(jsonString);
|
||||
|
||||
// Create a new Uint8Array and set its content to the encoded byte array
|
||||
const uint8Array = new Uint8Array(byteArray)
|
||||
const uint8Array = new Uint8Array(byteArray);
|
||||
|
||||
return uint8Array
|
||||
return uint8Array;
|
||||
}
|
||||
|
||||
export function uint8ArrayToBase64(uint8Array: Uint8Array): string {
|
||||
const length = uint8Array.length
|
||||
let binaryString = ''
|
||||
const chunkSize = 1024 * 1024 // Process 1MB at a time
|
||||
const length = uint8Array.length;
|
||||
let binaryString = "";
|
||||
const chunkSize = 1024 * 1024; // Process 1MB at a time
|
||||
|
||||
for (let i = 0; i < length; i += chunkSize) {
|
||||
const chunkEnd = Math.min(i + chunkSize, length)
|
||||
const chunk = uint8Array.subarray(i, chunkEnd)
|
||||
binaryString += Array.from(chunk, (byte) => String.fromCharCode(byte)).join(
|
||||
''
|
||||
)
|
||||
const chunkEnd = Math.min(i + chunkSize, length);
|
||||
const chunk = uint8Array.subarray(i, chunkEnd);
|
||||
binaryString += Array.from(chunk, byte => String.fromCharCode(byte)).join(
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
return btoa(binaryString)
|
||||
return btoa(binaryString);
|
||||
}
|
||||
|
||||
export function objectToUint8ArrayFromResponse(obj: any) {
|
||||
const len = Object.keys(obj).length
|
||||
const result = new Uint8Array(len)
|
||||
const len = Object.keys(obj).length;
|
||||
const result = new Uint8Array(len);
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
result[i] = obj[i]
|
||||
result[i] = obj[i];
|
||||
}
|
||||
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
// export function uint8ArrayToBase64(arrayBuffer: Uint8Array): string {
|
||||
// let binary = ''
|
||||
@ -99,46 +116,46 @@ export function objectToUint8ArrayFromResponse(obj: any) {
|
||||
// }
|
||||
|
||||
export function base64ToUint8Array(base64: string) {
|
||||
const binaryString = atob(base64)
|
||||
const len = binaryString.length
|
||||
const bytes = new Uint8Array(len)
|
||||
const binaryString = atob(base64);
|
||||
const len = binaryString.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i)
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
return bytes
|
||||
return bytes;
|
||||
}
|
||||
|
||||
export function uint8ArrayToObject(uint8Array: Uint8Array) {
|
||||
// Decode the byte array using TextDecoder
|
||||
const decoder = new TextDecoder()
|
||||
const jsonString = decoder.decode(uint8Array)
|
||||
const decoder = new TextDecoder();
|
||||
const jsonString = decoder.decode(uint8Array);
|
||||
|
||||
// Convert the JSON string back into an object
|
||||
const obj = JSON.parse(jsonString)
|
||||
const obj = JSON.parse(jsonString);
|
||||
|
||||
return obj
|
||||
return obj;
|
||||
}
|
||||
|
||||
export function processFileInChunks(file: File): Promise<Uint8Array> {
|
||||
return new Promise(
|
||||
(resolve: (value: Uint8Array) => void, reject: (reason?: any) => void) => {
|
||||
const reader = new FileReader()
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function (event: ProgressEvent<FileReader>) {
|
||||
const arrayBuffer = event.target?.result as ArrayBuffer
|
||||
const uint8Array = new Uint8Array(arrayBuffer)
|
||||
resolve(uint8Array)
|
||||
}
|
||||
const arrayBuffer = event.target?.result as ArrayBuffer;
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
resolve(uint8Array);
|
||||
};
|
||||
|
||||
reader.onerror = function (error: ProgressEvent<FileReader>) {
|
||||
reject(error)
|
||||
}
|
||||
reject(error);
|
||||
};
|
||||
|
||||
reader.readAsArrayBuffer(file)
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// export async function processFileInChunks(file: File, chunkSize = 1024 * 1024): Promise<Uint8Array> {
|
@ -18,7 +18,7 @@ export const fetchAndEvaluateVideos = async (data: any) => {
|
||||
service: content?.service || 'DOCUMENT',
|
||||
identifier: videoId
|
||||
})
|
||||
if (checkStructure(responseData)) {
|
||||
if (responseData) {
|
||||
obj = {
|
||||
...content,
|
||||
...responseData,
|
||||
|
Loading…
x
Reference in New Issue
Block a user