Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] added forceboot on developer settings #85

Merged
merged 4 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/contents/index/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,16 @@ function App(): JSX.Element {

const { info, settings } = streamInfo

const { "settings.display": displaySettings } = settings
const { "settings.display": displaySettings, "settings.developer": developerSettings } = settings

// 狀態為離綫時,此處不需要顯示按鈕
// 狀態為離綫時,除非强制啓動為 true
// 此處不需要顯示按鈕
// 離綫下載按鈕交給 feature UI 處理
if (info.status === 'offline') {
return <></>
}

const screenStatus = useWebScreenChange(settings['settings.developer'].classes)
const screenStatus = useWebScreenChange(developerSettings.classes)
const { bool: open, setFalse: closeDrawer, toggle } = useToggle(false)

const tutorialRef = useRef<TutorialRefProps>()
Expand Down
15 changes: 12 additions & 3 deletions src/contents/index/mounter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ContentContext from "~contexts/ContentContexts"
import type { FeatureType } from "~features"
import features from "~features"
import type { Settings } from "~options/fragments"
import { shouldInit } from "~options/fragments"
import { shouldInit } from "~options/shouldInit"
import { getStreamInfoByDom } from "~utils/bilibili"
import { injectAdapter } from "~utils/inject"
import { addBLiveMessageCommandListener, sendMessager } from "~utils/messaging"
Expand Down Expand Up @@ -60,7 +60,10 @@ function createMountPoints(plasmo: PlasmoSpec, info: StreamInfo): RootMountable[

const portals = await hook(settings, info)
// 返回禁用狀態的話則直接跳過渲染
if (!portals) {
if (typeof portals === 'string') {
toast.warning(portals, { position: 'top-center' })
return
} else if (!portals) {
console.info(`房間 ${info.room} 已被 ${key} 功能禁用,已略過`)
return
}
Expand Down Expand Up @@ -116,6 +119,7 @@ function createApp(roomId: string, plasmo: PlasmoSpec, info: StreamInfo): App {

const settings = await getFullSettingStroage()
const enabled = settings['settings.features'].enabledFeatures
const forceBoot = settings['settings.developer'].extra.forceBoot

// 如果沒有取得直播資訊,就嘗試使用 DOM 取得
if (!info) {
Expand All @@ -128,6 +132,11 @@ function createApp(roomId: string, plasmo: PlasmoSpec, info: StreamInfo): App {
return
}

// 強制啓動
if (forceBoot) {
info.status = 'online'
}

if (!(await shouldInit(settings, info))) {
console.info('不符合初始化條件,已略過')
return
Expand All @@ -141,7 +150,7 @@ function createApp(roomId: string, plasmo: PlasmoSpec, info: StreamInfo): App {
toast.warning('检测到你尚未登录, 本扩展的功能将会严重受限, 建议你先登录B站。', { position: 'top-center' })
}

// hook adapter (only when online)
// hook adapter (only when online or forceBoot)
if (info.status === 'online') {
console.info('開始注入適配器....')
const adapterType = settings["settings.capture"].captureMechanism
Expand Down
2 changes: 1 addition & 1 deletion src/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as recorder from './recorder'
import type { StreamInfo } from '~api/bilibili'
import type { Settings } from '~options/fragments'

export type FeatureHookRender = (settings: Readonly<Settings>, info: StreamInfo) => Promise<(React.ReactPortal | React.ReactNode)[] | undefined>
export type FeatureHookRender = (settings: Readonly<Settings>, info: StreamInfo) => Promise<(React.ReactPortal | React.ReactNode)[] | string | undefined>

export type FeatureAppRender = React.FC<{}>

Expand Down
2 changes: 1 addition & 1 deletion src/features/jimaku/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const handler: FeatureHookRender = async (settings, info) => {
if (noNativeVtuber && (await retryCatcher(() => isNativeVtuber(info.uid), 5))) {
// do log
console.info('檢測到為國V, 已略過')
return undefined // 返回 undefined 以禁用此功能
return undefined // 返回 undefined 以禁用此功能且不發送任何警告
}

return [
Expand Down
5 changes: 2 additions & 3 deletions src/features/recorder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import RecorderFeatureContext from "~contexts/RecorderFeatureContext";
import type { FeatureHookRender } from "~features";
import { sendMessager } from "~utils/messaging";
import RecorderLayer from "./components/RecorderLayer";
import { toast } from "sonner";

export const FeatureContext = RecorderFeatureContext

const handler: FeatureHookRender = async (settings, info) => {

const { error, data: urls } = await sendMessager('get-stream-urls', { roomId: info.room })
if (error) {
toast.error('启用快速切片功能失败: '+ error)
return undefined // disable the feature
console.warn('啟用快速切片功能失敗: ', error)
return '啟用快速切片功能失敗: '+ error // 返回 string 以顯示錯誤
}

return [
Expand Down
1 change: 1 addition & 0 deletions src/options/components/SettingFragment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const SettingFragmentContent = forwardRef(function SettingFragmentContent<T exte
useImperativeHandle(ref, () => ({
async saveSettings() {
if (!isModified()) return // if not modified, do nothing
console.debug('saving: ', fragmentKey, stateProxy.state)
await setSettingStorage<T, Schema<SettingFragments[T]>>(fragmentKey, { ...stateProxy.state }) // set the settings to storage
setBeforeSettings(deepCopy(stateProxy.state)) // update before settings so that to update check modified status
},
Expand Down
17 changes: 0 additions & 17 deletions src/options/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import * as features from './fragments/features'
import * as listings from './fragments/listings'
import * as version from './fragments/version'

import type { StreamInfo } from '~api/bilibili'


type ShouldInit<T extends object> = (settings: Readonly<T>, info: StreamInfo) => Promise<boolean>

interface SettingFragment<T extends object> {
defaultSettings: Readonly<T>
Expand All @@ -26,18 +22,6 @@ export type Settings = {
[K in keyof SettingFragments]: Schema<SettingFragments[K]>
}


export async function shouldInit(settings: Settings, info: StreamInfo): Promise<boolean> {
const shouldInits = Object.entries(fragments).map(([key, fragment]) => {
const shouldInit = (fragment as any).shouldInit as ShouldInit<Schema<typeof fragment>>
if (shouldInit) {
return shouldInit(settings[key], info)
}
return Promise.resolve(true)
})
return (await Promise.all(shouldInits)).every(Boolean)
}

// also defined the order of the settings
const fragments = {
'settings.features': features,
Expand All @@ -48,6 +32,5 @@ const fragments = {
'settings.version': version
}


export default fragments

72 changes: 55 additions & 17 deletions src/options/fragments/developer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Alert, Button, Input, Typography } from '@material-tailwind/react';
import { Fragment, type ChangeEvent } from 'react';
import { Alert, Button, Input, Switch, Typography } from '@material-tailwind/react';
import { Fragment, type ChangeEvent, type ExoticComponent } from 'react';
import { toast } from 'sonner/dist';
import type { ExposeHandler, StateProxy } from "~hooks/binding";
import type { Leaves } from "~types/common";
Expand Down Expand Up @@ -33,6 +33,9 @@ export type SettingSchema = {
chatUserId: string;
chatDanmaku: string;
};
extra: {
forceBoot: boolean;
};
};

export const defaultSettings: Readonly<SettingSchema> = {
Expand Down Expand Up @@ -61,13 +64,16 @@ export const defaultSettings: Readonly<SettingSchema> = {
attr: {
chatUserId: 'data-uid', // 聊天条 用户id 属性
chatDanmaku: 'data-danmaku' // 聊天条 弹幕 属性
},
extra: {
forceBoot: false // 在直播间下线时依然强制启动
}
}

export const title = '开发者相关'

export const description = [
'此设定区块是控制抓取元素的设定,这里的默认数值都是针对当前版本的B站页面。',
'此设定区块是控制抓取元素或其他实验性功能的设定,这里的默认数值都是针对当前版本的B站页面。',
'若B站页面发生改版, 本扩展将无法抓取元素致无法运作。除了等待本扩展的修复版本更新外, 有JS开发经验的用户可以自行修改此区块的数值以适应新版面。',
'至于没有JS开发经验的用户,则尽量不要碰这里的设定,否则有可能导致扩展无法正常运作。'
]
Expand All @@ -82,6 +88,11 @@ type ElementDefinerList = {
[title: string]: ElementDefiner[]
}

type ComponentDefiner<T> = {
Component: ExoticComponent<any>,
handler: (e: ChangeEvent<HTMLInputElement>) => T,
props?: (prop: { key: string, label: string, value: T, handler: (e: ChangeEvent<HTMLInputElement>) => T }) => object
}

const elementDefiners: ElementDefinerList = {
"元素捕捉": [
Expand Down Expand Up @@ -167,13 +178,33 @@ const elementDefiners: ElementDefinerList = {
label: "聊天条 弹幕 属性",
key: "attr.chatDanmaku"
},
],
"其他设定": [
{
label: "在直播间下线时依然强制启动",
key: "extra.forceBoot"
}
]
}

const componentDefiners: Record<string, ComponentDefiner<any>> = {
'string': {
Component: Input,
handler: (e: ChangeEvent<HTMLInputElement>) => e.target.value
},
'boolean': {
Component: Switch,
handler: (e: ChangeEvent<HTMLInputElement>) => e.target.checked,
props: ({ key, label, value, handler }) => ({
checked: value,
onChange: handler,
label: <Typography className="font-medium">{label}</Typography>
})
}
}

function DeveloperSettings({ state, useHandler }: StateProxy<SettingSchema>): JSX.Element {

const handler = useHandler<ChangeEvent<HTMLInputElement>, string>((e) => e.target.value)
function DeveloperSettings({ state, useHandler }: StateProxy<SettingSchema>): JSX.Element {

const alertIcon = (
<svg
Expand All @@ -192,15 +223,15 @@ function DeveloperSettings({ state, useHandler }: StateProxy<SettingSchema>): JS

const fetchDeveloper = async () => {
if (!window.confirm('这将覆盖开发者相关所有目前设定。')) return
const fetching = (async function(){
const fetching = (async function () {
const { data, error } = await sendMessager('fetch-developer')
if (error) throw new Error(error)
await setSettingStorage('settings.developer', data)
})()
toast.promise(fetching, {
loading: '正在获取远端最新开发者设定...',
success: '已成功获取最新版本,请重新加载网页。',
error: (err) => '获取最新版本失败: '+err.message
error: (err) => '获取最新版本失败: ' + err.message
})
await fetching
}
Expand All @@ -226,16 +257,23 @@ function DeveloperSettings({ state, useHandler }: StateProxy<SettingSchema>): JS
<Typography variant="h3">
{title}
</Typography>
{definers.map(({ label, key }) => (
<Input
data-testid={key}
key={key}
crossOrigin="anonymous"
variant="static"
label={label}
value={(state as ExposeHandler<SettingSchema>).get(key)}
onChange={handler(key)} />
))}
{definers.map(({ label, key }) => {
const value = (state as ExposeHandler<SettingSchema>).get(key)
const { Component, handler, props } = componentDefiners[typeof value]
const onChange = useHandler<ChangeEvent<HTMLInputElement>, typeof value>(handler)(key)
return (
<Component
data-testid={key}
key={key}
crossOrigin="anonymous"
{...(props ? props({ key, label, value, handler: onChange }) : {
value,
label,
onChange,
})}
/>
)
})}
</Fragment>
))}
</div>
Expand Down
30 changes: 0 additions & 30 deletions src/options/fragments/features.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useCallback, type ChangeEvent } from 'react';
import { ensureIsVtuber, type StreamInfo } from '~api/bilibili';
import SwitchListItem from '~options/components/SwitchListItem';
import { sendMessager } from '~utils/messaging';

Expand Down Expand Up @@ -230,34 +229,5 @@ function TrashIconButton({ table, title }: { table: TableType, title: string }):
);
}

export async function shouldInit(settings: SettingSchema, info: StreamInfo): Promise<boolean> {

if (!info) {
// do log
console.info('無法取得直播資訊,已略過')
return false
}

if (info.status === 'offline' && settings.enabledRecording.length === 0) {
console.info('直播為下綫狀態,且沒有啓用離綫儲存,已略過。')
return false
}

if (settings.common.onlyVtuber) {

if (info.uid !== '0') {
await ensureIsVtuber(info)
}

if (!info.isVtuber) {
// do log
console.info('不是 VTuber, 已略過')
return false
}

}

return true
}

export default FeatureSettings
8 changes: 0 additions & 8 deletions src/options/fragments/listings.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

import { Fragment, type ChangeEvent } from 'react';
import { type StreamInfo } from '~api/bilibili';
import DataTable, { type TableHeader } from '~options/components/DataTable';
import { removeArr } from '~utils/misc';

Expand Down Expand Up @@ -87,12 +86,5 @@ function ListingSettings({ state, useHandler }: StateProxy<SettingSchema>): JSX.
)
}

export async function shouldInit(settings: Readonly<SettingSchema>, info: StreamInfo): Promise<boolean> {
if (settings.blackListRooms.some((r) => r.room === info.room || r.room === info.shortRoom) === !settings.useAsWhiteListRooms) {
console.info('房間已被列入黑名單,已略過')
return false
}
return true
}

export default ListingSettings
45 changes: 45 additions & 0 deletions src/options/shouldInit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Settings } from "~options/fragments"
import { type StreamInfo, ensureIsVtuber } from "~api/bilibili"

export async function shouldInit(settings: Settings, info: StreamInfo): Promise<boolean> {

const {
"settings.features": features,
"settings.listings": listings,
"settings.developer": developer
} = settings

// features
if (!info) {
// do log
console.info('無法取得直播資訊,已略過')
return false
}

if (info.status === 'offline' && features.enabledRecording.length === 0 && !developer.extra.forceBoot) {
console.info('直播為下綫狀態,且沒有啓用離綫儲存,已略過。(强制啓動為禁用)')
return false
}

if (features.common.onlyVtuber) {

if (info.uid !== '0') {
await ensureIsVtuber(info)
}

if (!info.isVtuber) {
// do log
console.info('不是 VTuber, 已略過')
return false
}

}

// listings
if (listings.blackListRooms.some((r) => r.room === info.room || r.room === info.shortRoom) === !listings.useAsWhiteListRooms) {
console.info('房間已被列入黑名單,已略過')
return false
}

return true;
}
Loading
Loading