3 Commits
1.9.0 ... 1.9.1

Author SHA1 Message Date
IndieKKY
c40338a5f5 chore: release 1.9.1 2024-03-19 22:23:55 +08:00
IndieKKY
13e90c1ab7 上下键移动 2024-03-19 22:22:39 +08:00
IndieKKY
9b2d620cdf Revert "去除是否自动展开配置"
This reverts commit e6db6747
2024-03-19 21:39:16 +08:00
14 changed files with 116 additions and 29 deletions

View File

@@ -1,7 +1,7 @@
{
"name": "哔哩哔哩字幕列表",
"description": "显示B站视频的字幕列表,可点击跳转与下载字幕,并支持翻译和总结字幕!",
"version": "1.9.0",
"version": "1.9.1",
"manifest_version": 3,
"permissions": [
"storage"

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "bilibili-subtitle",
"version": "1.9.0",
"version": "1.9.1",
"type": "module",
"description": "哔哩哔哩字幕列表",
"main": "index.js",

View File

@@ -43,6 +43,7 @@ import {getSummarize} from '../util/biz_util'
import {openUrl} from '@kky002/kky-util'
import Markdown from '../components/Markdown'
import {random} from 'lodash-es'
import useKeyService from '../hooks/useKeyService'
const Body = () => {
const dispatch = useAppDispatch()
@@ -207,6 +208,9 @@ const Body = () => {
dispatch(setAskFold(!askFold))
}, [askFold, dispatch])
// service
useKeyService()
// 自动滚动
useEffect(() => {
if (checkAutoScroll && curOffsetTop && autoScroll && !needScroll) {
@@ -304,6 +308,13 @@ const Body = () => {
segmentIdx={segmentIdx} bodyRef={bodyRef}/>)}
{/* tip */}
<div className='text-sm font-semibold text-center'></div>
<ul className='list-disc text-sm desc pl-5'>
<li>+</li>
<li>alt+</li>
<li>(使)</li>
</ul>
{/* <div className='flex flex-col items-center text-center pt-1 pb-2'> */}
{/* <div className='font-semibold text-accent'>💡<span className='underline underline-offset-4'>提示</span>💡</div> */}
{/* <div className='text-sm desc px-2'>可以尝试将<span className='text-amber-600 font-semibold'>概览</span>生成的内容粘贴到<span */}
@@ -313,8 +324,8 @@ const Body = () => {
{/* onClick={onCopy}>点击复制生成的{SUMMARIZE_TYPES[curSummaryType].name}<RiFileCopy2Line/> */}
{/* </button>} */}
{/* </div> */}
{((infos == null) || infos.length === 0) && <div className='flex flex-col'>
<div className='flex flex-col items-center text-center py-2 mx-4'>
<div className='flex flex-col'>
<div className='flex flex-col items-center text-center py-2 mx-4 border-t border-t-base-300'>
<div className='font-semibold text-accent flex items-center gap-1'><img src='/bibigpt.png'
alt='BibiGPT logo'
className='w-8 h-8'/>BibiGPT
@@ -349,7 +360,8 @@ const Body = () => {
e.preventDefault()
openUrl('https://microsoftedge.microsoft.com/addons/detail/galeejdehabppfgooagmkclpppnbccpc')
}} className='link text-sm text-accent'>Edge商店</a>
<a title='Crx搜搜(国内可访问)' href='https://www.crxsoso.com/webstore/detail/fiaeclpicddpifeflpmlgmbjgaedladf'
<a title='Crx搜搜(国内可访问)'
href='https://www.crxsoso.com/webstore/detail/fiaeclpicddpifeflpmlgmbjgaedladf'
onClick={(e) => {
e.preventDefault()
openUrl('https://www.crxsoso.com/webstore/detail/fiaeclpicddpifeflpmlgmbjgaedladf')
@@ -376,7 +388,7 @@ const Body = () => {
}} className='link text-sm text-accent'>Crx搜搜(访)</a>
</div>
</div>
</div>}
</div>
</div>
{/* recommend */}
@@ -417,7 +429,8 @@ const Body = () => {
}}><img src='/openai-up.ico'
alt='Openai Up logo'
className='w-8 h-8'/>Openai代理</a>
<span className='text-sm desc flex items-center'>6<FaGripfire className='text-amber-600'/></span>
<span className='text-sm desc flex items-center'>6<FaGripfire
className='text-amber-600'/></span>
</div>}
</div>
</div>

View File

@@ -9,8 +9,9 @@ const CompactSegmentItem = (props: {
isIn: boolean
last: boolean
moveCallback: (event: any) => void
move2Callback: (event: any) => void
}) => {
const {item, idx, last, isIn, moveCallback} = props
const {item, idx, last, isIn, moveCallback, move2Callback} = props
const transResult = useAppSelector(state => state.env.transResults[idx])
const envData = useAppSelector(state => state.env.envData)
const fontSize = useAppSelector(state => state.env.envData.fontSize)
@@ -19,7 +20,7 @@ const CompactSegmentItem = (props: {
const display = useMemo(() => getDisplay(envData.transDisplay, item.content, transText), [envData.transDisplay, item.content, transText])
return <div className={classNames('inline', fontSize === 'large'?'text-sm':'text-xs')}>
<span className={'pl-1 pr-0.5 py-0.5 cursor-pointer rounded-sm hover:bg-base-200'} onClick={moveCallback}>
<span className={'pl-1 pr-0.5 py-0.5 cursor-pointer rounded-sm hover:bg-base-200'} onClick={moveCallback} onDoubleClick={move2Callback}>
<text className={classNames('font-medium', isIn ? 'text-primary underline' : '')}>{display.main}</text>
{display.sub && <text className='desc'>({display.sub})</text>}</span>
<span className='text-base-content/75'>{!last && ','}</span>

View File

@@ -9,8 +9,9 @@ const NormalSegmentItem = (props: {
idx: number
isIn: boolean
moveCallback: (event: any) => void
move2Callback: (event: any) => void
}) => {
const {item, idx, isIn, moveCallback} = props
const {item, idx, isIn, moveCallback, move2Callback} = props
const transResult = useAppSelector(state => state.env.transResults[idx])
const envData = useAppSelector(state => state.env.envData)
const fontSize = useAppSelector(state => state.env.envData.fontSize)
@@ -19,7 +20,7 @@ const NormalSegmentItem = (props: {
const display = useMemo(() => getDisplay(envData.transDisplay, item.content, transText), [envData.transDisplay, item.content, transText])
return <div className={classNames('flex py-0.5 cursor-pointer rounded-sm hover:bg-base-200', fontSize === 'large'?'text-sm':'text-xs')}
onClick={moveCallback}>
onClick={moveCallback} onDoubleClick={move2Callback}>
<div className='desc w-[66px] flex justify-center'>{formatTime(item.from)}</div>
<div className={'flex-1'}>
<div className={classNames('font-medium', isIn ? 'text-primary underline' : '')}>{display.main}</div>

View File

@@ -46,7 +46,7 @@ const SummarizeItemOverview = (props: {
if (event.altKey) { // 复制
navigator.clipboard.writeText(overviewItem.key).catch(console.error)
} else {
move(time)
move(time, false)
}
}, [overviewItem.key, move, time])

View File

@@ -33,7 +33,15 @@ const SegmentItem = (props: {
if (event.altKey) { // 复制
navigator.clipboard.writeText(item.content).catch(console.error)
} else {
move(item.from)
move(item.from, false)
}
}, [item.content, item.from, move])
const move2Callback = useCallback((event: any) => {
if (event.altKey) { // 复制
navigator.clipboard.writeText(item.content).catch(console.error)
} else {
move(item.from, true)
}
}, [item.content, item.from, move])
@@ -63,6 +71,7 @@ const SegmentItem = (props: {
isIn={isIn}
last={last}
moveCallback={moveCallback}
move2Callback={move2Callback}
/>
:
<NormalSegmentItem
@@ -70,6 +79,7 @@ const SegmentItem = (props: {
idx={idx}
isIn={isIn}
moveCallback={moveCallback}
move2Callback={move2Callback}
/>
}
</span>

View File

@@ -56,7 +56,7 @@ const FormItem = (props: {
const Settings = () => {
const dispatch = useAppDispatch()
const envData = useAppSelector(state => state.env.envData)
// const {value: autoExpandValue, onChange: setAutoExpandValue} = useEventChecked(envData.autoExpand)
const {value: autoExpandValue, onChange: setAutoExpandValue} = useEventChecked(envData.autoExpand)
// const {value: autoScrollValue, onChange: setAutoScrollValue} = useEventChecked(envData.autoScroll)
const {value: translateEnableValue, onChange: setTranslateEnableValue} = useEventChecked(envData.translateEnable)
const {value: summarizeEnableValue, onChange: setSummarizeEnableValue} = useEventChecked(envData.summarizeEnable)
@@ -109,7 +109,7 @@ const Settings = () => {
const onSave = useCallback(() => {
dispatch(setEnvData({
// autoExpand: autoExpandValue,
autoExpand: autoExpandValue,
aiType: aiTypeValue,
apiKey: apiKeyValue,
serverUrl: serverUrlValue,
@@ -133,7 +133,7 @@ const Settings = () => {
}))
dispatch(setPage(PAGE_MAIN))
toast.success('保存成功')
}, [dispatch, aiTypeValue, apiKeyValue, serverUrlValue, modelValue, geminiApiKeyValue, translateEnableValue, languageValue, hideOnDisableAutoTranslateValue, themeValue, transDisplayValue, summarizeEnableValue, summarizeFloatValue, summarizeLanguageValue, wordsValue, fetchAmountValue, fontSizeValue, promptsValue, searchEnabledValue, cnSearchEnabledValue, askEnabledValue])
}, [dispatch, autoExpandValue, aiTypeValue, apiKeyValue, serverUrlValue, modelValue, geminiApiKeyValue, translateEnableValue, languageValue, hideOnDisableAutoTranslateValue, themeValue, transDisplayValue, summarizeEnableValue, summarizeFloatValue, summarizeLanguageValue, wordsValue, fetchAmountValue, fontSizeValue, promptsValue, searchEnabledValue, cnSearchEnabledValue, askEnabledValue])
const onCancel = useCallback(() => {
dispatch(setPage(PAGE_MAIN))
@@ -192,10 +192,10 @@ const Settings = () => {
}}>
<div className="flex flex-col gap-3 p-2">
<Section title='通用配置'>
{/* <FormItem title='自动展开' htmlFor='autoExpand' tip='是否视频有字幕时自动展开字幕列表'> */}
{/* <input id='autoExpand' type='checkbox' className='toggle toggle-primary' checked={autoExpandValue} */}
{/* onChange={setAutoExpandValue}/> */}
{/* </FormItem> */}
<FormItem title='自动展开' htmlFor='autoExpand' tip='是否视频有字幕时自动展开字幕列表'>
<input id='autoExpand' type='checkbox' className='toggle toggle-primary' checked={autoExpandValue}
onChange={setAutoExpandValue}/>
</FormItem>
<FormItem title='主题'>
<div className="btn-group">
<button onClick={onSelTheme1} className={classNames('btn btn-xs no-animation', (!themeValue || themeValue === 'system')?'btn-active':'')}></button>

View File

@@ -158,6 +158,9 @@ window.addEventListener("message", (event) => {
const video = getVideoElement()
if (video) {
video.currentTime = data.time
if (data.togglePause) {
video.paused ? video.play() : video.pause()
}
}
}

View File

@@ -0,0 +1,59 @@
import {useEffect} from 'react'
import {useMemoizedFn} from 'ahooks/es'
import {useAppSelector} from './redux'
import useSubtitle from './useSubtitle'
const useKeyService = () => {
const curIdx = useAppSelector(state => state.env.curIdx)
const data = useAppSelector(state => state.env.data)
const {move} = useSubtitle()
const onKeyDown = useMemoizedFn((e: KeyboardEvent) => {
// 有按其他控制键时,不触发
if (e.ctrlKey || e.metaKey || e.shiftKey) {
return
}
let cursorInInput = false
if (document.activeElement != null) {
const tagName = document.activeElement.tagName
if (tagName === 'INPUT' || tagName === 'TEXTAREA') {
cursorInInput = true
}
}
let prevent = false
// up arrow
if (e.key === 'ArrowUp') {
if (curIdx && (data != null) && !cursorInInput) {
prevent = true
const newCurIdx = Math.max(curIdx - 1, 0)
move(data.body[newCurIdx].from, false)
}
}
// down arrow
if (e.key === 'ArrowDown') {
if (curIdx !== undefined && (data != null) && !cursorInInput) {
prevent = true
const newCurIdx = Math.min(curIdx + 1, data.body.length - 1)
move(data.body[newCurIdx].from, false)
}
}
// 阻止默认事件
if (prevent) {
e.preventDefault()
e.stopPropagation()
}
})
// 检测快捷键
useEffect(() => {
document.addEventListener('keydown', onKeyDown)
return () => {
document.removeEventListener('keydown', onKeyDown)
}
}, [onKeyDown])
}
export default useKeyService

View File

@@ -5,8 +5,8 @@ import {setNeedScroll} from '../redux/envReducer'
const useSubtitle = () => {
const dispatch = useAppDispatch()
const move = useCallback((time: number) => {
window.parent.postMessage({type: 'move', time}, '*')
const move = useCallback((time: number, togglePause: boolean) => {
window.parent.postMessage({type: 'move', time, togglePause}, '*')
}, [])
const scrollIntoView = useCallback((ref: React.RefObject<HTMLDivElement>) => {

View File

@@ -100,20 +100,20 @@ const useSubtitleService = () => {
// 有数据时自动展开
useEffect(() => {
if (infos != null) {
if ((data != null) && data.body.length > 0) {
eventBus.emit({
type: EVENT_EXPAND
})
}
}, [eventBus, infos])
}, [data, eventBus, infos])
// 当前未展示 & 未折叠 & 有列表 => 展示第一个
// 当前未展示 & (未折叠 | 自动展开) & 有列表 => 展示第一个
useEffect(() => {
if (!curInfo && !fold && (infos != null) && infos.length > 0) {
if (!curInfo && (!fold || (envReady && envData.autoExpand)) && (infos != null) && infos.length > 0) {
dispatch(setCurInfo(infos[0]))
dispatch(setCurFetched(false))
}
}, [curInfo, dispatch, envReady, fold, infos])
}, [curInfo, dispatch, envData.autoExpand, envReady, fold, infos])
// 获取
useEffect(() => {
if (curInfo && !curFetched) {

View File

@@ -54,7 +54,7 @@ const initialState: EnvState = {
serverUrl: SERVER_URL_OPENAI,
translateEnable: true,
summarizeEnable: true,
// autoExpand: true,
autoExpand: true,
theme: 'light',
searchEnabled: true,
},

2
src/typings.d.ts vendored
View File

@@ -1,5 +1,5 @@
interface EnvData {
// autoExpand?: boolean
autoExpand?: boolean
flagDot?: boolean
aiType?: 'openai' | 'gemini'