You've already forked bilibili-subtitle
init
This commit is contained in:
6
src/hooks/redux.ts
Normal file
6
src/hooks/redux.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import {TypedUseSelectorHook, useDispatch, useSelector} from 'react-redux'
|
||||
import type {AppDispatch, RootState} from '../store'
|
||||
|
||||
// Use throughout your app instead of plain `useDispatch` and `useSelector`
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
|
20
src/hooks/useSubtitle.ts
Normal file
20
src/hooks/useSubtitle.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {useAppDispatch} from './redux'
|
||||
import React, {useCallback} from 'react'
|
||||
import {setNeedScroll} from '../redux/envReducer'
|
||||
|
||||
const useSubtitle = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
|
||||
const move = useCallback((time: number) => {
|
||||
window.parent.postMessage({type: 'move', time}, '*')
|
||||
}, [])
|
||||
|
||||
const scrollIntoView = useCallback((ref: React.RefObject<HTMLDivElement>) => {
|
||||
ref.current?.scrollIntoView({behavior: 'smooth', block: 'center'})
|
||||
dispatch(setNeedScroll(false))
|
||||
}, [dispatch])
|
||||
|
||||
return {move, scrollIntoView}
|
||||
}
|
||||
|
||||
export default useSubtitle
|
219
src/hooks/useSubtitleService.ts
Normal file
219
src/hooks/useSubtitleService.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
import {useAppDispatch, useAppSelector} from './redux'
|
||||
import {useContext, useEffect} from 'react'
|
||||
import {
|
||||
setCurFetched,
|
||||
setCurIdx,
|
||||
setCurInfo,
|
||||
setCurrentTime,
|
||||
setData,
|
||||
setInfos,
|
||||
setNoVideo,
|
||||
setSegmentFold,
|
||||
setSegments,
|
||||
setTitle,
|
||||
setTotalHeight,
|
||||
} from '../redux/envReducer'
|
||||
import {EventBusContext} from '../Router'
|
||||
import {EVENT_EXPAND, TOTAL_HEIGHT_MAX, TOTAL_HEIGHT_MIN, WORDS_DEFAULT, WORDS_MAX, WORDS_MIN} from '../const'
|
||||
import {useInterval} from 'ahooks'
|
||||
import {getWholeText} from '../util/biz_util'
|
||||
|
||||
/**
|
||||
* Service是单例,类似后端的服务概念
|
||||
*/
|
||||
const useSubtitleService = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const infos = useAppSelector(state => state.env.infos)
|
||||
const curInfo = useAppSelector(state => state.env.curInfo)
|
||||
const curFetched = useAppSelector(state => state.env.curFetched)
|
||||
const fold = useAppSelector(state => state.env.fold)
|
||||
const envReady = useAppSelector(state => state.env.envReady)
|
||||
const envData = useAppSelector(state => state.env.envData)
|
||||
const data = useAppSelector(state => state.env.data)
|
||||
const currentTime = useAppSelector(state => state.env.currentTime)
|
||||
const curIdx = useAppSelector(state => state.env.curIdx)
|
||||
const eventBus = useContext(EventBusContext)
|
||||
const needScroll = useAppSelector(state => state.env.needScroll)
|
||||
const segments = useAppSelector(state => state.env.segments)
|
||||
const transResults = useAppSelector(state => state.env.transResults)
|
||||
const hideOnDisableAutoTranslate = useAppSelector(state => state.env.envData.hideOnDisableAutoTranslate)
|
||||
const autoTranslate = useAppSelector(state => state.env.autoTranslate)
|
||||
|
||||
// 设置屏安具
|
||||
|
||||
// 监听消息
|
||||
useEffect(() => {
|
||||
const listener = (event: MessageEvent) => {
|
||||
const data = event.data
|
||||
|
||||
if (data.type === 'setVideoInfo') {
|
||||
dispatch(setInfos(data.infos))
|
||||
dispatch(setTitle(data.title))
|
||||
console.debug('video title: ', data.title)
|
||||
}
|
||||
|
||||
if (data.type === 'setInfos') {
|
||||
dispatch(setInfos(data.infos))
|
||||
dispatch(setCurInfo(undefined))
|
||||
dispatch(setCurFetched(false))
|
||||
dispatch(setData(undefined))
|
||||
// console.log('setInfos', data.infos)
|
||||
}
|
||||
|
||||
if (data.type === 'setSubtitle') {
|
||||
const data_ = data.data.data
|
||||
data_?.body?.forEach((item: TranscriptItem, idx: number) => {
|
||||
item.idx = idx
|
||||
})
|
||||
// dispatch(setCurInfo(data.data.info))
|
||||
dispatch(setCurFetched(true))
|
||||
dispatch(setData(data_))
|
||||
// console.log('setSubtitle', data.data)
|
||||
}
|
||||
|
||||
if (data.type === 'setCurrentTime') {
|
||||
dispatch(setCurrentTime(data.data.currentTime))
|
||||
}
|
||||
if (data.type === 'setSettings') {
|
||||
dispatch(setNoVideo(data.data.noVideo))
|
||||
if (data.data.totalHeight) {
|
||||
dispatch(setTotalHeight(Math.min(Math.max(data.data.totalHeight, TOTAL_HEIGHT_MIN), TOTAL_HEIGHT_MAX)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', listener)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('message', listener)
|
||||
}
|
||||
}, [dispatch, eventBus])
|
||||
|
||||
// 有数据时自动展开
|
||||
useEffect(() => {
|
||||
if ((data != null) && data.body.length > 0) {
|
||||
eventBus.emit({
|
||||
type: EVENT_EXPAND
|
||||
})
|
||||
}
|
||||
}, [data, eventBus])
|
||||
|
||||
// 当前未展示 & (未折叠 | 自动展开) & 有列表 => 展示第一个
|
||||
useEffect(() => {
|
||||
if (!curInfo && (!fold || (envReady && envData.autoExpand)) && (infos != null) && infos.length > 0) {
|
||||
dispatch(setCurInfo(infos[0]))
|
||||
dispatch(setCurFetched(false))
|
||||
}
|
||||
}, [curInfo, dispatch, envData.autoExpand, envReady, fold, infos])
|
||||
// 获取
|
||||
useEffect(() => {
|
||||
if (curInfo && !curFetched) {
|
||||
window.parent.postMessage({type: 'getSubtitle', info: curInfo}, '*')
|
||||
}
|
||||
}, [curFetched, curInfo])
|
||||
|
||||
useEffect(() => {
|
||||
// 初始获取列表
|
||||
window.parent.postMessage({type: 'refreshVideoInfo'}, '*')
|
||||
// 初始获取设置信息
|
||||
window.parent.postMessage({type: 'getSettings'}, '*')
|
||||
}, [])
|
||||
|
||||
// 更新当前位置
|
||||
useEffect(() => {
|
||||
let curIdx
|
||||
if (((data?.body) != null) && currentTime) {
|
||||
for (let i=0; i<data.body.length; i++) {
|
||||
const item = data.body[i]
|
||||
if (item.from && currentTime < item.from) {
|
||||
break
|
||||
} else {
|
||||
curIdx = i
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatch(setCurIdx(curIdx))
|
||||
}, [currentTime, data?.body, dispatch])
|
||||
|
||||
// 需要滚动 => segment自动展开
|
||||
useEffect(() => {
|
||||
if (needScroll && curIdx != null) { // 需要滚动
|
||||
for (const segment of segments??[]) { // 检测segments
|
||||
if (segment.startIdx <= curIdx && curIdx <= segment.endIdx) { // 找到对应的segment
|
||||
if (segment.fold) { // 需要展开
|
||||
dispatch(setSegmentFold({
|
||||
segmentStartIdx: segment.startIdx,
|
||||
fold: false
|
||||
}))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [curIdx, dispatch, needScroll, segments])
|
||||
|
||||
// data等变化时自动刷新segments
|
||||
useEffect(() => {
|
||||
let segments: Segment[] | undefined
|
||||
const items = data?.body
|
||||
if (items != null) {
|
||||
if (envData.summarizeEnable) { // 分段
|
||||
let size = envData.words??WORDS_DEFAULT
|
||||
size = Math.min(Math.max(size, WORDS_MIN), WORDS_MAX)
|
||||
|
||||
segments = []
|
||||
let transcriptItems: TranscriptItem[] = []
|
||||
let totalLength = 0
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
transcriptItems.push(item)
|
||||
totalLength += item.content.length
|
||||
if (totalLength >= size || i === items.length-1) { // new segment or last
|
||||
// add
|
||||
segments.push({
|
||||
items: transcriptItems,
|
||||
startIdx: transcriptItems[0].idx,
|
||||
endIdx: transcriptItems[transcriptItems.length - 1].idx,
|
||||
text: getWholeText(transcriptItems.map(item => item.content)),
|
||||
summaries: {},
|
||||
})
|
||||
// reset
|
||||
transcriptItems = []
|
||||
totalLength = 0
|
||||
}
|
||||
}
|
||||
} else { // 都放一个分段
|
||||
segments = [{
|
||||
items,
|
||||
startIdx: 0,
|
||||
endIdx: items.length-1,
|
||||
text: getWholeText(items.map(item => item.content)),
|
||||
summaries: {},
|
||||
}]
|
||||
}
|
||||
}
|
||||
dispatch(setSegments(segments))
|
||||
}, [data?.body, dispatch, envData.summarizeEnable, envData.words])
|
||||
|
||||
// 每秒更新当前视频时间
|
||||
useInterval(() => {
|
||||
window.parent.postMessage({type: 'getCurrentTime'}, '*')
|
||||
}, 500)
|
||||
|
||||
// show translated text in the video
|
||||
useEffect(() => {
|
||||
if (hideOnDisableAutoTranslate && !autoTranslate) {
|
||||
window.parent.postMessage({type: 'updateTransResult'}, '*')
|
||||
return
|
||||
}
|
||||
|
||||
const transResult = curIdx?transResults[curIdx]:undefined
|
||||
if (transResult?.code === '200' && transResult.data) {
|
||||
window.parent.postMessage({type: 'updateTransResult', result: transResult.data}, '*')
|
||||
} else {
|
||||
window.parent.postMessage({type: 'updateTransResult'}, '*')
|
||||
}
|
||||
}, [autoTranslate, curIdx, hideOnDisableAutoTranslate, transResults])
|
||||
}
|
||||
|
||||
export default useSubtitleService
|
310
src/hooks/useTranslate.ts
Normal file
310
src/hooks/useTranslate.ts
Normal file
@@ -0,0 +1,310 @@
|
||||
import {useAppDispatch, useAppSelector} from './redux'
|
||||
import {useCallback} from 'react'
|
||||
import {
|
||||
addTaskId,
|
||||
addTransResults,
|
||||
delTaskId,
|
||||
setLastSummarizeTime,
|
||||
setLastTransTime,
|
||||
setSummaryContent,
|
||||
setSummaryError,
|
||||
setSummaryStatus
|
||||
} from '../redux/envReducer'
|
||||
import {
|
||||
LANGUAGE_DEFAULT,
|
||||
LANGUAGES_MAP,
|
||||
SUMMARIZE_LANGUAGE_DEFAULT,
|
||||
SUMMARIZE_THRESHOLD,
|
||||
TRANSLATE_COOLDOWN,
|
||||
TRANSLATE_FETCH_DEFAULT,
|
||||
} from '../const'
|
||||
import toast from 'react-hot-toast'
|
||||
import {useMemoizedFn} from 'ahooks/es'
|
||||
import {extractJsonArray, extractJsonObject} from '../util/biz_util'
|
||||
import {formatTime} from '../util/util'
|
||||
|
||||
const useTranslate = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const data = useAppSelector(state => state.env.data)
|
||||
const curIdx = useAppSelector(state => state.env.curIdx)
|
||||
const lastTransTime = useAppSelector(state => state.env.lastTransTime)
|
||||
const transResults = useAppSelector(state => state.env.transResults)
|
||||
const envData = useAppSelector(state => state.env.envData)
|
||||
const language = LANGUAGES_MAP[envData.language??LANGUAGE_DEFAULT]
|
||||
const summarizeLanguage = LANGUAGES_MAP[envData.summarizeLanguage??SUMMARIZE_LANGUAGE_DEFAULT]
|
||||
|
||||
/**
|
||||
* 获取下一个需要翻译的行
|
||||
* 会检测冷却
|
||||
*/
|
||||
const getFetch = useCallback(() => {
|
||||
if (data?.body != null && data.body.length > 0) {
|
||||
const curIdx_ = curIdx ?? 0
|
||||
|
||||
// check lastTransTime
|
||||
if (lastTransTime && Date.now() - lastTransTime < TRANSLATE_COOLDOWN) {
|
||||
return
|
||||
}
|
||||
|
||||
let nextIdleIdx
|
||||
for (let i = curIdx_; i < data.body.length; i++) {
|
||||
if (transResults[i] == null) {
|
||||
nextIdleIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (nextIdleIdx != null && nextIdleIdx - curIdx_ <= Math.ceil((envData.fetchAmount??TRANSLATE_FETCH_DEFAULT)/2)) {
|
||||
return nextIdleIdx
|
||||
}
|
||||
}
|
||||
}, [curIdx, data?.body, envData.fetchAmount, lastTransTime, transResults])
|
||||
|
||||
const addTask = useCallback(async (startIdx: number) => {
|
||||
if ((data?.body) != null) {
|
||||
const lines: string[] = data.body.slice(startIdx, startIdx + (envData.fetchAmount??TRANSLATE_FETCH_DEFAULT)).map((item: any) => item.content)
|
||||
if (lines.length > 0) {
|
||||
const linesMap: {[key: string]: string} = {}
|
||||
lines.forEach((line, idx) => {
|
||||
linesMap[(idx + 1)+''] = line
|
||||
})
|
||||
let lineStr = JSON.stringify(linesMap).replaceAll('\n', '')
|
||||
lineStr = '```' + lineStr + '```'
|
||||
const taskDef: TaskDef = {
|
||||
type: 'chatComplete',
|
||||
serverUrl: envData.serverUrl,
|
||||
data: {
|
||||
model: 'gpt-3.5-turbo',
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a professional translator.'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: `Translate following video subtitles to language '${language.name}'.
|
||||
Preserve incomplete sentence.
|
||||
Translate in the same json format.
|
||||
Answer in markdown json format.
|
||||
|
||||
video subtitles:
|
||||
|
||||
\`\`\`
|
||||
${lineStr}
|
||||
\`\`\``
|
||||
}
|
||||
],
|
||||
temperature: 0,
|
||||
n: 1,
|
||||
stream: false,
|
||||
},
|
||||
extra: {
|
||||
type: 'translate',
|
||||
apiKey: envData.apiKey,
|
||||
startIdx,
|
||||
size: lines.length,
|
||||
}
|
||||
}
|
||||
console.debug('addTask', taskDef)
|
||||
dispatch(setLastTransTime(Date.now()))
|
||||
// addTransResults
|
||||
const result: { [key: number]: TransResult } = {}
|
||||
lines.forEach((line, idx) => {
|
||||
result[startIdx + idx] = {
|
||||
// idx: startIdx + idx,
|
||||
}
|
||||
})
|
||||
dispatch(addTransResults(result))
|
||||
const task = await chrome.runtime.sendMessage({type: 'addTask', taskDef})
|
||||
dispatch(addTaskId(task.id))
|
||||
}
|
||||
}
|
||||
}, [data?.body, dispatch, envData.apiKey, envData.fetchAmount, envData.serverUrl, language.name])
|
||||
|
||||
const addSummarizeTask = useCallback(async (title: string | undefined, type: SummaryType, segment: Segment) => {
|
||||
if (segment.text.length >= SUMMARIZE_THRESHOLD && envData.apiKey) {
|
||||
const title_ = title?`The video's title is '${title}'.`:''
|
||||
let subtitles = ''
|
||||
for (const item of segment.items) {
|
||||
subtitles += formatTime(item.from) + ' ' + item.content + '\n'
|
||||
}
|
||||
let content
|
||||
if (type === 'overview') {
|
||||
content = `You are a helpful assistant that summarize key points of video subtitle.
|
||||
Summarize 3 to 8 brief key points in language '${summarizeLanguage.name}'.
|
||||
Answer in markdown json format.
|
||||
The emoji should be related to the key point and 1 char length.
|
||||
|
||||
example output format:
|
||||
|
||||
\`\`\`json
|
||||
[
|
||||
{
|
||||
"time": "03:00",
|
||||
"emoji": "👍",
|
||||
"key": "key point 1"
|
||||
},
|
||||
{
|
||||
"time": "10:05",
|
||||
"emoji": "😊",
|
||||
"key": "key point 2"
|
||||
}
|
||||
]
|
||||
\`\`\`
|
||||
|
||||
The video's title: '''${title_}'''.
|
||||
The video's subtitles:
|
||||
|
||||
'''
|
||||
${subtitles}
|
||||
'''`
|
||||
} else if (type === 'keypoint') {
|
||||
content = `You are a helpful assistant that summarize key points of video subtitle.
|
||||
Summarize brief key points in language '${summarizeLanguage.name}'.
|
||||
Answer in markdown json format.
|
||||
|
||||
example output format:
|
||||
|
||||
\`\`\`json
|
||||
[
|
||||
"key point 1",
|
||||
"key point 2"
|
||||
]
|
||||
\`\`\`
|
||||
|
||||
The video's title: '''${title_}'''.
|
||||
The video's subtitles:
|
||||
|
||||
'''
|
||||
${segment.text}
|
||||
'''`
|
||||
} else if (type === 'brief') {
|
||||
content = `You are a helpful assistant that summarize video subtitle.
|
||||
Summarize in language '${summarizeLanguage.name}'.
|
||||
Answer in markdown json format.
|
||||
|
||||
example output format:
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"summary": "brief summary"
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
The video's title: '''${title_}'''.
|
||||
The video's subtitles:
|
||||
|
||||
'''
|
||||
${segment.text}
|
||||
'''`
|
||||
}
|
||||
const taskDef: TaskDef = {
|
||||
type: 'chatComplete',
|
||||
serverUrl: envData.serverUrl,
|
||||
data: {
|
||||
model: 'gpt-3.5-turbo',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
content,
|
||||
}
|
||||
],
|
||||
temperature: 0,
|
||||
n: 1,
|
||||
stream: false,
|
||||
},
|
||||
extra: {
|
||||
type: 'summarize',
|
||||
summaryType: type,
|
||||
startIdx: segment.startIdx,
|
||||
apiKey: envData.apiKey,
|
||||
}
|
||||
}
|
||||
console.debug('addSummarizeTask', taskDef)
|
||||
dispatch(setSummaryStatus({segmentStartIdx: segment.startIdx, type, status: 'pending'}))
|
||||
dispatch(setLastSummarizeTime(Date.now()))
|
||||
const task = await chrome.runtime.sendMessage({type: 'addTask', taskDef})
|
||||
dispatch(addTaskId(task.id))
|
||||
}
|
||||
}, [dispatch, envData.apiKey, envData.serverUrl, summarizeLanguage.name])
|
||||
|
||||
const handleTranslate = useMemoizedFn((task: Task, content: string) => {
|
||||
let map: {[key: string]: string} = {}
|
||||
try {
|
||||
content = extractJsonObject(content)
|
||||
map = JSON.parse(content)
|
||||
} catch (e) {
|
||||
console.debug(e)
|
||||
}
|
||||
const {startIdx, size} = task.def.extra
|
||||
if (startIdx != null) {
|
||||
const result: { [key: number]: TransResult } = {}
|
||||
for (let i = 0; i < size; i++) {
|
||||
const item = map[(i + 1)+'']
|
||||
if (item) {
|
||||
result[startIdx + i] = {
|
||||
// idx: startIdx + i,
|
||||
code: '200',
|
||||
data: item,
|
||||
}
|
||||
} else {
|
||||
result[startIdx + i] = {
|
||||
// idx: startIdx + i,
|
||||
code: '500',
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatch(addTransResults(result))
|
||||
console.debug('addTransResults', map, size)
|
||||
}
|
||||
})
|
||||
|
||||
const handleSummarize = useMemoizedFn((task: Task, content?: string) => {
|
||||
const summaryType = task.def.extra.summaryType
|
||||
content = summaryType === 'brief'?extractJsonObject(content??''):extractJsonArray(content??'')
|
||||
let obj
|
||||
try {
|
||||
obj = JSON.parse(content)
|
||||
} catch (e) {
|
||||
task.error = 'failed'
|
||||
}
|
||||
|
||||
dispatch(setSummaryContent({
|
||||
segmentStartIdx: task.def.extra.startIdx,
|
||||
type: summaryType,
|
||||
content: obj,
|
||||
}))
|
||||
dispatch(setSummaryStatus({segmentStartIdx: task.def.extra.startIdx, type: summaryType, status: 'done'}))
|
||||
dispatch(setSummaryError({segmentStartIdx: task.def.extra.startIdx, type: summaryType, error: task.error}))
|
||||
console.debug('setSummary', task.def.extra.startIdx, summaryType, obj, task.error)
|
||||
})
|
||||
|
||||
const getTask = useCallback(async (taskId: string) => {
|
||||
const taskResp = await chrome.runtime.sendMessage({type: 'getTask', taskId})
|
||||
if (taskResp.code === 'ok') {
|
||||
console.debug('getTask', taskResp.task)
|
||||
const task: Task = taskResp.task
|
||||
const taskType: string | undefined = task.def.extra?.type
|
||||
const content = task.resp?.choices?.[0]?.message?.content?.trim()
|
||||
if (task.status === 'done') {
|
||||
// 异常提示
|
||||
if (task.error) {
|
||||
toast.error(task.error)
|
||||
}
|
||||
// 删除任务
|
||||
dispatch(delTaskId(taskId))
|
||||
// 处理结果
|
||||
if (taskType === 'translate') { // 翻译
|
||||
handleTranslate(task, content)
|
||||
} else if (taskType === 'summarize') { // 总结
|
||||
handleSummarize(task, content)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dispatch(delTaskId(taskId))
|
||||
}
|
||||
}, [dispatch, handleSummarize, handleTranslate])
|
||||
|
||||
return {getFetch, getTask, addTask, addSummarizeTask}
|
||||
}
|
||||
|
||||
export default useTranslate
|
55
src/hooks/useTranslateService.ts
Normal file
55
src/hooks/useTranslateService.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import {useAppDispatch, useAppSelector} from './redux'
|
||||
import {useEffect} from 'react'
|
||||
import {clearTransResults} from '../redux/envReducer'
|
||||
import {useInterval, useMemoizedFn} from 'ahooks'
|
||||
import useTranslate from './useTranslate'
|
||||
|
||||
/**
|
||||
* Service是单例,类似后端的服务概念
|
||||
*/
|
||||
const useTranslateService = () => {
|
||||
const dispatch = useAppDispatch()
|
||||
const autoTranslate = useAppSelector(state => state.env.autoTranslate)
|
||||
const data = useAppSelector(state => state.env.data)
|
||||
const taskIds = useAppSelector(state => state.env.taskIds)
|
||||
const curIdx = useAppSelector(state => state.env.curIdx)
|
||||
const {getFetch, addTask, getTask} = useTranslate()
|
||||
|
||||
// data变化时清空翻译结果
|
||||
useEffect(() => {
|
||||
dispatch(clearTransResults())
|
||||
console.debug('清空翻译结果')
|
||||
}, [data, dispatch])
|
||||
|
||||
// autoTranslate开启时立即查询
|
||||
const addTaskNow = useMemoizedFn(() => {
|
||||
addTask(curIdx??0).catch(console.error)
|
||||
})
|
||||
useEffect(() => {
|
||||
if (autoTranslate) {
|
||||
addTaskNow()
|
||||
console.debug('立即查询翻译')
|
||||
}
|
||||
}, [autoTranslate, addTaskNow])
|
||||
|
||||
// 每3秒检测翻译
|
||||
useInterval(async () => {
|
||||
if (autoTranslate) {
|
||||
const fetchStartIdx = getFetch()
|
||||
if (fetchStartIdx != null) {
|
||||
await addTask(fetchStartIdx)
|
||||
}
|
||||
}
|
||||
}, 3000)
|
||||
|
||||
// 每0.5秒检测获取结果
|
||||
useInterval(async () => {
|
||||
if (taskIds != null) {
|
||||
for (const taskId of taskIds) {
|
||||
await getTask(taskId)
|
||||
}
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
export default useTranslateService
|
Reference in New Issue
Block a user