generated from vivid-lapin/ts
-
Notifications
You must be signed in to change notification settings - Fork 6
/
plugin.ts
239 lines (217 loc) · 8.24 KB
/
plugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
import type { EventEmitter } from "events"
import React from "react"
import * as Recoil from "recoil"
import { Program, Service } from "../infra/mirakurun/api"
export type { Channel, Service, Program } from "../infra/mirakurun/api"
import { ContentPlayerPlayingContent } from "./contentPlayer"
import {
OpenBuiltinWindowArg,
OpenContentPlayerWindowArgs,
OpenWindowArg,
Preload,
} from "./ipc"
import { MirakurunCompatibilityTypes } from "./mirakurun"
import {
ControllerSetting,
ExperimentalSetting,
ScreenshotSetting,
SubtitleSetting,
} from "./setting"
export type { ContentPlayerPlayingContent } from "./contentPlayer"
export type AppInfo = {
name: string
version: string
}
export type CustomComponent = {
id: string
component: React.FC<{}>
}
/** すべてのウィンドウに展開される。見えない。 */
export type OnBackgroundComponent = {
position: "onBackground"
} & CustomComponent
/** ほぼ見えない。バックグラウンド実行用などに */
export type OnSplashComponent = { position: "onSplash" } & CustomComponent
/** プラグイン設定画面 */
export type OnSettingComponent = {
position: "onSetting"
label: string
} & CustomComponent
/** コントローラーのポップアップに出る。小さなコンポーネントにすること */
export type OnControllerPopupComponent = {
position: "OnControllerPopup"
} & CustomComponent
/** プレイヤーの上、字幕より後ろ */
export type OnPlayerComponent = { position: "onPlayer" } & CustomComponent
/** 字幕より上、コントローラーより後ろ */
export type OnSubtitleComponent = { position: "onSubtitle" } & CustomComponent
/** 一番前、pointer-events: noneのため触りたい場合は該当部分だけautoにしておくこと */
export type OnForwardComponent = { position: "onForward" } & CustomComponent
export type ComponentWithPosition =
| OnBackgroundComponent
| OnSplashComponent
| OnSettingComponent
| OnControllerPopupComponent
| OnPlayerComponent
| OnSubtitleComponent
| OnForwardComponent
export type InitPlugin = {
main?: InitPluginInMain
renderer?: InitPluginInRenderer
}
export type PluginInRendererArgs = {
appInfo: AppInfo
rpc: Preload["public"]
windowId: number
functions: {
openWindow: (args: OpenWindowArg) => Promise<number>
openBuiltinWindow: (args: OpenBuiltinWindowArg) => Promise<void>
openContentPlayerWindow: (
args: OpenContentPlayerWindowArgs
) => Promise<number>
}
hooks: {}
atoms: {
globalContentPlayerIdsSelector: Recoil.RecoilValueReadOnly<number[]>
globalContentPlayerPlayingContentFamily: (
n: number
) => Recoil.RecoilState<ContentPlayerPlayingContent | null>
globalActiveContentPlayerIdSelector: Recoil.RecoilValueReadOnly<
number | null
>
globalContentPlayerSelectedServiceFamily: (
n: number
) => Recoil.RecoilState<Service | null>
globalContentPlayerIsPlayingFamily: (
n: number
) => Recoil.RecoilState<boolean>
contentPlayerPlayingContentAtom: Recoil.RecoilState<ContentPlayerPlayingContent | null>
contentPlayerServiceSelector: Recoil.RecoilValueReadOnly<Service | null>
contentPlayerProgramSelector: Recoil.RecoilValueReadOnly<Program | null>
contentPlayerIsPlayingAtom: Recoil.RecoilState<boolean>
contentPlayerVolumeAtom: Recoil.RecoilState<number>
contentPlayerSpeedAtom: Recoil.RecoilState<number>
contentPlayerAudioChannelAtom: Recoil.RecoilState<number>
contentPlayerAudioTrackAtom: Recoil.RecoilState<number>
contentPlayerAudioTracksSelector: Recoil.RecoilValueReadOnly<string[]>
contentPlayerIsSeekableSelector: Recoil.RecoilValueReadOnly<boolean>
contentPlayerPlayingPositionSelector: Recoil.RecoilValueReadOnly<number>
contentPlayerPlayingTimeSelector: Recoil.RecoilValueReadOnly<number>
contentPlayerTotSelector: Recoil.RecoilValueReadOnly<number>
contentPlayerAribSubtitleDataSelector: Recoil.RecoilValueReadOnly<number>
contentPlayerTsFirstPcrSelector: Recoil.RecoilValueReadOnly<number>
contentPlayerPositionUpdateTriggerAtom: Recoil.RecoilState<number>
contentPlayerScreenshotTriggerAtom: Recoil.RecoilState<number>
contentPlayerScreenshotUrlSelector: Recoil.RecoilValueReadOnly<
string | null
>
mirakurunCompatibilitySelector: Recoil.RecoilValueReadOnly<MirakurunCompatibilityTypes | null>
mirakurunVersionSelector: Recoil.RecoilValueReadOnly<string | null>
mirakurunServicesSelector: Recoil.RecoilValueReadOnly<Service[] | null>
controllerSettingSelector: Recoil.RecoilValueReadOnly<ControllerSetting>
subtitleSettingSelector: Recoil.RecoilValueReadOnly<SubtitleSetting>
screenshotSettingSelector: Recoil.RecoilValueReadOnly<ScreenshotSetting>
experimentalSettingSelector: Recoil.RecoilValueReadOnly<ExperimentalSetting>
}
constants: {
recoil: {
sharedKey: string
storedKey: string
}
}
}
export type InitPluginInRenderer = (
args: PluginInRendererArgs
) => PluginDefineInRenderer | Promise<PluginDefineInRenderer>
export type PluginInMainArgs = {
appInfo: AppInfo
packages: {
Electron: {
app: Electron.App
browserWindow: typeof Electron.BrowserWindow
dialog: Electron.Dialog
ipcMain: Electron.IpcMain
session: typeof Electron.Session
}
events: {
eventEmitter: EventEmitter
}
}
functions: {
openWindow: (args: OpenWindowArg) => Electron.BrowserWindow
openBuiltinWindow: (args: OpenBuiltinWindowArg) => void
openContentPlayerWindow: (args: OpenContentPlayerWindowArgs) => void
}
}
export type InitPluginInMain = (
args: PluginInMainArgs
) => PluginDefineInMain | Promise<PluginDefineInMain>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Atom<T = any> = {
type: "atom"
atom: Recoil.RecoilState<T>
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type AtomFamily<A = any, T = any> = {
type: "family"
atom: (arg: A) => Recoil.RecoilState<T>
key: string
arg: A
}
export type DefineAtom = Atom | AtomFamily
export type PluginMeta = {
/** 推奨 id フォーマット: `plugins.${authorNamespace}.${pluginNamespace}` or `io.github.c..`(java 形式) */
id: string
name: string
version: string
author: string
authorUrl?: string
description: string
url?: string
/** 現時点で正しく実行される保証はない、セットアップが正常に終了していなくても呼ばれる点に注意 */
destroy: () => void | Promise<void>
}
export type PluginDefineInRenderer = PluginMeta & {
setup: ({
plugins,
}: {
plugins: PluginDefineInRenderer[]
}) => void | Promise<void>
/** 他のプラグインと連携するとか
* 重要: atom の key は `plugins.${authorNamespace}.${pluginNamespace}.` から開始、大きくルールに反する atom (`plugins.`から開始しない)を露出したプラグインはロードされない */
exposedAtoms: DefineAtom[]
/** ウィンドウ間で共有する Atom(シリアライズ可能にすること)
* @deprecated 後方互換性のためのフィールドです、同時に Atom に syncEffect も設定してください */
sharedAtoms?: DefineAtom[]
/** 保存する Atom(シリアライズ可能にすること)。
* @deprecated 後方互換性のためのフィールドです、同時に Atom に syncEffect も設定してください */
storedAtoms?: DefineAtom[]
/** コンポーネントとウィンドウは shadowRoot に展開されるので、各自独自に CSS をバンドルしないとスタイリングが初期化される点に注意する */
components: ComponentWithPosition[]
windows: {
/** カスタム画面、hash を key に */
[key: string]: React.FC<{}>
}
_experimental_feature__service?: {
/** テレビサービス(構想中) */
contentType: string
restoreByKey: (
arg: unknown
) =>
| ContentPlayerPlayingContent
| null
| Promise<ContentPlayerPlayingContent | null>
}
}
export type InternalPluginDefineInRenderer = PluginDefineInRenderer & {
fileName: string
}
export type PluginDefineInMain = PluginMeta & {
setup: ({
plugins,
}: {
plugins: PluginDefineInMain[]
}) => void | Promise<void>
appMenu?: Electron.MenuItemConstructorOptions
contextMenu?: Electron.MenuItemConstructorOptions
}