Skip to content
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: 7 additions & 0 deletions packages/danmaku-anywhere/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export const manifest = defineManifest({
js: ['src/content/app/index.ts'],
run_at: 'document_start',
},
{
matches: ['https://*/*', 'http://*/*'],
js: ['src/content/player/index.ts'],
run_at: 'document_start',
all_frames: true,
// isolated world by default
},
],
permissions,
host_permissions: ['https://*/*', 'http://*/*', 'file:///*'],
Expand Down
60 changes: 17 additions & 43 deletions packages/danmaku-anywhere/src/background/rpc/RpcManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
import { setRequestHeaderRule } from '@danmaku-anywhere/web-scraper'
import { inject, injectable } from 'inversify'
import { match } from 'ts-pattern'
import { ScriptingManager } from '@/background/scripting/ScriptingManager'
import { BackupService } from '@/background/services/Backup/BackupService.service'
import { DataManagementService } from '@/background/services/DataManagementService'
import { GenAIService } from '@/background/services/GenAIService'
Expand Down Expand Up @@ -64,7 +63,6 @@ export class RpcManager {
@inject(EpisodeMatchingService)
private episodeMatchingService: EpisodeMatchingService,
@inject(LogService) private logService: LogService,
@inject(ScriptingManager) private scriptingManager: ScriptingManager,
@inject(DanmakuAnywhereDb) private db: DanmakuAnywhereDb,
@inject(LoggerSymbol) logger: ILogger,
@inject(DebugFileService) private debugFileService: DebugFileService,
Expand Down Expand Up @@ -207,21 +205,6 @@ export class RpcManager {
void invalidateContentScriptData(sender.tab?.id)
return result
},
getAllFrames: async (_, sender) => {
if (sender.tab?.id === undefined) {
throw new RpcException('No tab id found')
}

const tabId = sender.tab.id

const frames = await chrome.webNavigation.getAllFrames({ tabId })

if (!frames) {
throw new RpcException('No frames found')
}

return frames
},
getExtensionManifest: async () => {
return chrome.runtime.getManifest() as chrome.runtime.ManifestV3
},
Expand All @@ -239,17 +222,6 @@ export class RpcManager {

return sender.frameId
},
injectScript: async (frameId, sender) => {
this.logger.debug('Injecting script into frame', { frameId })

if (sender.tab?.id === undefined) {
throw new RpcException('No tab id found')
}

const tabId = sender.tab.id

await this.scriptingManager.injectVideoScript(tabId, frameId)
},
remoteLog: async (data) => {
void this.logService.log(data)
},
Expand Down Expand Up @@ -377,25 +349,21 @@ export class RpcManager {
const passThrough = <TRPCDef extends AnyRPCDef>(
clientMethod: TabRPCClientMethod<TRPCDef>
): RRPServerHandler<TRPCDef> => {
return async (data, sender, setContext) => {
return async (data, sender, setContext, options) => {
// Apparently tab.index can be -1 in some cases, this will cause an error so we need to handle it
const tabIndex =
sender.tab?.index === -1 ? undefined : sender.tab?.index

const res = await clientMethod(
data,
{},
{
tabInfo: { windowId: sender.tab?.windowId, index: tabIndex },
getTab: (tabs) => {
const tab = tabs.find((tab) => tab.id === sender.tab?.id)
if (!tab) {
throw new RpcException('Tab not found')
}
return tab
},
}
)
const res = await clientMethod(data, options, {
tabInfo: { windowId: sender.tab?.windowId, index: tabIndex },
getTab: (tabs) => {
const tab = tabs.find((tab) => tab.id === sender.tab?.id)
if (!tab) {
throw new RpcException('Tab not found')
}
return tab
},
})
setContext(res.context)
return res.data
}
Expand All @@ -421,9 +389,15 @@ export class RpcManager {
'relay:command:enterPip': passThrough(
relayFrameClient['relay:command:enterPip']
),
'relay:command:controllerReady': passThrough(
relayFrameClient['relay:command:controllerReady']
),
'relay:event:playerReady': passThrough(
relayFrameClient['relay:event:playerReady']
),
'relay:event:playerUnload': passThrough(
relayFrameClient['relay:event:playerUnload']
),
'relay:event:videoChange': passThrough(
relayFrameClient['relay:event:videoChange']
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { createTaskQueue } from '@/common/utils/taskQueue'
// the ?script query is used to get the file path for the script after bundling
// @ts-expect-error
import contentScript from '@/content/controller?script'
// @ts-expect-error
import testScript from '@/content/player?script'

const contentScriptId = 'main-content'

Expand Down Expand Up @@ -50,16 +48,6 @@ export class ScriptingManager {
})
}

async injectVideoScript(tabId: number, frameId: number) {
this.logger.debug('Injecting player script into tab', { tabId, frameId })

await chrome.scripting.executeScript({
target: { tabId, frameIds: [frameId] },
files: [testScript],
world: 'ISOLATED',
})
}

private async handleContentScriptRegistration(mountConfigs: MountConfig[]) {
const patterns = mountConfigs
// only register enabled configs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@
"exported": "Export successful",
"exportError": "Export failed: {{message}}",
"fetchError": "Failed to fetch danmaku: {{message}}",
"frameListEmpty": "Browser returned an empty frame list, this likely indicates a bug in the browser.",
"mounted_one": "Danmaku Mounted: {{name}} ({{count}})",
"mounted_other": "Danmaku Mounted: {{name}} ({{count}})",
"mountedMultiple_one": "Mounted {{count}} selected danmaku",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@
"exported": "导出成功",
"exportError": "导出失败:{{message}}",
"fetchError": "获取弹幕失败:{{message}}",
"frameListEmpty": "浏览器返回的Frame列表为空,这可能是浏览器的bug。",
"mounted_other": "弹幕已装填:{{name}} ({{count}})",
"mountedMultiple_other": "已装填{{count}}个多选弹幕",
"mountError": "装填弹幕失败:{{message}}",
Expand Down
20 changes: 16 additions & 4 deletions packages/danmaku-anywhere/src/common/rpc/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,41 @@ const createPayload = <TInput>(
}
}

// Intentionally cast: optional calls return undefined data, which doesn't match
// the declared output type. All optional callers should discard the return value.
// biome-ignore lint/suspicious/noExplicitAny: see above
const emptyResponse = { data: undefined, context: {} } as RPCClientResponse<any>

const handleRpcResponse = <TRecords extends RPCRecord>(
result: RPCResponse<TRecords[string]['output']> | null,
method: string,
err: Error | null
err: Error | null,
options?: RpcOptions
): RPCClientResponse<TRecords[string]> => {
if (err) {
if (options?.optional) return emptyResponse
throw new RpcException(err.message, { cause: err })
}

// if message is not handled, result will be undefined, we treat that as an error
if (!result) {
if (options?.optional) return emptyResponse
throw new RpcException(
`Method ${method} returned undefined. This likely means the method is not handled by the server.`
)
}

if (result.state === 'errored') {
if (options?.optional) {
console.warn(`[RPC] Optional call "${method}" errored:`, result.error)
return emptyResponse
}
throw new RpcException(result.error, {
cause: result.detail ? deserializeError(result.detail) : undefined,
})
}

if (result.state === 'ignored') {
if (options?.optional) return emptyResponse
throw new RpcException(
`Method ${method} is explicitly ignored by the server.`
)
Expand All @@ -100,7 +112,7 @@ export const createChromeRpcClient = <
chromeSender(createPayload(method, input, options))
)

return handleRpcResponse(result, method, err)
return handleRpcResponse(result, method, err, options)
}
},
}
Expand Down Expand Up @@ -128,7 +140,7 @@ export const createContentRpcClient = <
)
)

return handleRpcResponse(result, method, err)
return handleRpcResponse(result, method, err, options)
}
},
}
Expand Down
Loading
Loading