154 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { getUploadToken, uploadToQiniu } from "@/api/common";
import { useState, useCallback, useEffect } from "react";
import { ScriptEditKey } from "../usecase/ScriptEditUseCase";
/**
* 渲染数据转换器
* @param key
* @param headerName
* @param scriptText
* @returns
*/
export function parseScriptBlock(
key: ScriptEditKey,
headerName: string,
scriptText: string,
contentType?: "paragraph" | "bold" | "italic" | "heading" | "tag"
) {
return {
id: key,
title: headerName,
content: [
{
type: contentType || "paragraph",
text: scriptText,
},
],
};
}
/**
* 用于上传文件到七牛云的自定义 Hook
* @returns {object} - 包含上传函数和加载状态
*/
export function useUploadFile() {
/** 加载状态 */
const [isUploading, setIsUploading] = useState(false);
/**
* 上传文件到七牛云
* @param {File} file - 要上传的文件
* @param {(progress: number) => void} [onProgress] - 上传进度回调
* @returns {Promise<string>} - 上传后文件的 URL
* @throws {Error} - 上传失败时抛出异常
*/
const uploadFile = useCallback(
async (
file: File,
onProgress?: (progress: number) => void
): Promise<string> => {
try {
setIsUploading(true);
const { token } = await getUploadToken();
const fileUrl = await uploadToQiniu(file, token, onProgress);
return fileUrl;
} catch (err) {
console.error("文件上传失败:", err);
throw err;
} finally {
setIsUploading(false);
}
},
[]
);
return { uploadFile, isUploading };
}
/**加载文案定时变 */
export function useLoadScriptText(loading: boolean): { loadingText: string } {
// 如果loading 为true 则每五秒切换一次文本如果变false 则停止切换,且重置文本位置
const tests = [
"loading...",
"Brainstorming initial story concepts and themes.",
"Drafting the screenplay's first outline.",
"Refining character arcs and plot points.",
"Finalizing the script with dialogue polish.",
"Creating detailed storyboards for key scenes.",
"Scouting potential filming locations.",
"Designing mood boards for visual aesthetics.",
"Casting actors to bring characters to life.",
"Scheduling production timelines and shoots.",
"Securing permits for on-location filming.",
"Building sets to match the storys vision.",
"Designing costumes for character authenticity.",
"Planning lighting setups for each scene.",
"Renting equipment for high-quality production.",
"Rehearsing actors for seamless performances.",
"Setting up cameras for the first shot.",
"Filming establishing shots for scene context.",
"Capturing key dialogue scenes with precision.",
"Recording action sequences with dynamic angles.",
"Filming close-ups to capture emotions.",
"Wrapping principal photography on set.",
"Reviewing dailies for quality assurance.",
"Organizing raw footage for editing.",
"Editing scenes for narrative flow.",
"Adding sound effects to enhance immersion.",
"Composing the films musical score.",
"Mixing audio for balanced sound design.",
"Applying color grading for visual consistency.",
"Rendering visual effects for final polish.",
"Exporting the final cut for distribution.",
];
const [currentIndex, setCurrentIndex] = useState(0);
const [intervalId, setIntervalId] = useState<NodeJS.Timeout | null>(null);
useEffect(() => {
if (loading) {
const interval = setInterval(() => {
setCurrentIndex((prev) => (prev + 1) % tests.length);
}, 5000);
setIntervalId(interval);
} else {
if (intervalId) {
clearInterval(intervalId);
setIntervalId(null);
setCurrentIndex(0);
}
}
return () => {
if (intervalId) {
clearInterval(intervalId);
setIntervalId(null);
setCurrentIndex(0);
}
};
}, [loading, tests.length]);
return { loadingText: tests[currentIndex] };
}
/**
* 获取音频文件时长
* @param {File | Blob} audioFile - 音频文件或Blob
* @returns {Promise<number>} 音频时长(秒)
*/
export const getAudioDuration = (audioFile: File | Blob): Promise<number> => {
return new Promise((resolve, reject) => {
const audio = new Audio();
const url = URL.createObjectURL(audioFile);
audio.addEventListener('loadedmetadata', () => {
const duration = audio.duration;
URL.revokeObjectURL(url);
resolve(duration);
});
audio.addEventListener('error', (error) => {
URL.revokeObjectURL(url);
reject(new Error(`无法读取音频文件: ${error.message}`));
});
audio.src = url;
});
};