easyrip 3.13.2__py3-none-any.whl → 4.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- easyrip/__init__.py +5 -1
- easyrip/__main__.py +124 -15
- easyrip/easyrip_command.py +457 -148
- easyrip/easyrip_config/config.py +269 -0
- easyrip/easyrip_config/config_key.py +28 -0
- easyrip/easyrip_log.py +120 -42
- easyrip/easyrip_main.py +509 -259
- easyrip/easyrip_mlang/__init__.py +20 -45
- easyrip/easyrip_mlang/global_lang_val.py +18 -16
- easyrip/easyrip_mlang/lang_en.py +1 -1
- easyrip/easyrip_mlang/lang_zh_Hans_CN.py +101 -77
- easyrip/easyrip_mlang/translator.py +12 -10
- easyrip/easyrip_prompt.py +73 -0
- easyrip/easyrip_web/__init__.py +2 -1
- easyrip/easyrip_web/http_server.py +56 -42
- easyrip/easyrip_web/third_party_api.py +60 -8
- easyrip/global_val.py +21 -1
- easyrip/ripper/media_info.py +10 -3
- easyrip/ripper/param.py +482 -0
- easyrip/ripper/ripper.py +260 -574
- easyrip/ripper/sub_and_font/__init__.py +10 -0
- easyrip/ripper/{font_subset → sub_and_font}/ass.py +95 -84
- easyrip/ripper/{font_subset → sub_and_font}/font.py +72 -79
- easyrip/ripper/{font_subset → sub_and_font}/subset.py +122 -81
- easyrip/utils.py +129 -27
- easyrip-4.9.1.dist-info/METADATA +92 -0
- easyrip-4.9.1.dist-info/RECORD +31 -0
- easyrip/easyrip_config.py +0 -198
- easyrip/ripper/__init__.py +0 -10
- easyrip/ripper/font_subset/__init__.py +0 -7
- easyrip-3.13.2.dist-info/METADATA +0 -89
- easyrip-3.13.2.dist-info/RECORD +0 -29
- {easyrip-3.13.2.dist-info → easyrip-4.9.1.dist-info}/WHEEL +0 -0
- {easyrip-3.13.2.dist-info → easyrip-4.9.1.dist-info}/entry_points.txt +0 -0
- {easyrip-3.13.2.dist-info → easyrip-4.9.1.dist-info}/licenses/LICENSE +0 -0
- {easyrip-3.13.2.dist-info → easyrip-4.9.1.dist-info}/top_level.txt +0 -0
easyrip/easyrip_command.py
CHANGED
|
@@ -1,16 +1,48 @@
|
|
|
1
1
|
import enum
|
|
2
|
+
import itertools
|
|
2
3
|
import textwrap
|
|
4
|
+
from collections.abc import Iterable
|
|
3
5
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Self
|
|
6
|
+
from typing import Final, Self, final
|
|
7
|
+
|
|
8
|
+
from prompt_toolkit.completion import (
|
|
9
|
+
Completer,
|
|
10
|
+
DeduplicateCompleter,
|
|
11
|
+
FuzzyCompleter,
|
|
12
|
+
FuzzyWordCompleter,
|
|
13
|
+
NestedCompleter,
|
|
14
|
+
WordCompleter,
|
|
15
|
+
merge_completers,
|
|
16
|
+
)
|
|
17
|
+
from prompt_toolkit.completion.base import CompleteEvent, Completion
|
|
18
|
+
from prompt_toolkit.document import Document
|
|
5
19
|
|
|
6
20
|
from . import global_val
|
|
21
|
+
from .easyrip_config.config_key import Config_key
|
|
22
|
+
from .ripper.param import Audio_codec, Preset_name
|
|
7
23
|
|
|
8
24
|
|
|
25
|
+
@final
|
|
9
26
|
@dataclass(slots=True, init=False, eq=False)
|
|
10
27
|
class Cmd_type_val:
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
names: tuple[str, ...]
|
|
29
|
+
_param: str
|
|
13
30
|
_description: str
|
|
31
|
+
childs: tuple["Cmd_type_val", ...]
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def param(self) -> str:
|
|
35
|
+
try:
|
|
36
|
+
from .easyrip_mlang import gettext
|
|
37
|
+
|
|
38
|
+
return gettext(self._param, is_format=False)
|
|
39
|
+
|
|
40
|
+
except ImportError: # 启动时,原字符串导入翻译文件
|
|
41
|
+
return self._param
|
|
42
|
+
|
|
43
|
+
@param.setter
|
|
44
|
+
def param(self, val: str) -> None:
|
|
45
|
+
self._param = val
|
|
14
46
|
|
|
15
47
|
@property
|
|
16
48
|
def description(self) -> str:
|
|
@@ -23,56 +55,58 @@ class Cmd_type_val:
|
|
|
23
55
|
return self._description
|
|
24
56
|
|
|
25
57
|
@description.setter
|
|
26
|
-
def description(self, val: str):
|
|
58
|
+
def description(self, val: str) -> None:
|
|
27
59
|
self._description = val
|
|
28
60
|
|
|
29
61
|
def __init__(
|
|
30
62
|
self,
|
|
31
|
-
|
|
63
|
+
names: tuple[str, ...],
|
|
32
64
|
*,
|
|
33
|
-
|
|
65
|
+
param: str = "",
|
|
34
66
|
description: str = "",
|
|
67
|
+
childs: tuple["Cmd_type_val", ...] = (),
|
|
35
68
|
) -> None:
|
|
36
|
-
self.
|
|
37
|
-
self.
|
|
69
|
+
self.names = names
|
|
70
|
+
self.param = param
|
|
38
71
|
self.description = description
|
|
72
|
+
self.childs = childs
|
|
39
73
|
|
|
40
74
|
def __eq__(self, other: object) -> bool:
|
|
41
75
|
if isinstance(other, Cmd_type_val):
|
|
42
|
-
return self.
|
|
76
|
+
return self.names == other.names
|
|
43
77
|
return False
|
|
44
78
|
|
|
45
79
|
def __hash__(self) -> int:
|
|
46
|
-
return hash(self.
|
|
80
|
+
return hash(self.names)
|
|
47
81
|
|
|
48
82
|
def to_doc(self) -> str:
|
|
49
|
-
return (
|
|
50
|
-
f"{self.opt_str}\n{textwrap.indent(self.description, ' │', lambda _: True)}"
|
|
51
|
-
)
|
|
83
|
+
return f"{' / '.join(self.names)} {self.param}\n{textwrap.indent(self.description, ' │ ', lambda _: True)}"
|
|
52
84
|
|
|
53
85
|
|
|
54
86
|
class Cmd_type(enum.Enum):
|
|
55
87
|
help = h = Cmd_type_val(
|
|
56
|
-
"help",
|
|
57
|
-
|
|
58
|
-
description=
|
|
88
|
+
("h", "help"),
|
|
89
|
+
param="[<cmd> [<cmd param>]]",
|
|
90
|
+
description=(
|
|
91
|
+
"Show full help or show the <cmd> help.\n"
|
|
92
|
+
"e.g. help list\n" # .
|
|
93
|
+
"e.g. h -p x265slow"
|
|
94
|
+
),
|
|
59
95
|
)
|
|
60
96
|
version = v = ver = Cmd_type_val(
|
|
61
|
-
"version",
|
|
62
|
-
opt_str="v / ver / version",
|
|
97
|
+
("v", "ver", "version"),
|
|
63
98
|
description="Show version info",
|
|
64
99
|
)
|
|
65
100
|
init = Cmd_type_val(
|
|
66
|
-
"init",
|
|
67
|
-
opt_str="init",
|
|
101
|
+
("init",),
|
|
68
102
|
description=(
|
|
69
103
|
"Execute initialization function\n"
|
|
70
104
|
"e.g. you can execute it after modifying the dynamic translation file"
|
|
71
105
|
),
|
|
72
106
|
)
|
|
73
107
|
log = Cmd_type_val(
|
|
74
|
-
"log",
|
|
75
|
-
|
|
108
|
+
("log",),
|
|
109
|
+
param="[<LogLevel>] <string>",
|
|
76
110
|
description=(
|
|
77
111
|
"Output custom log\n"
|
|
78
112
|
"log level:\n"
|
|
@@ -83,10 +117,17 @@ class Cmd_type(enum.Enum):
|
|
|
83
117
|
" debug\n"
|
|
84
118
|
" Default: info"
|
|
85
119
|
),
|
|
120
|
+
childs=(
|
|
121
|
+
Cmd_type_val(("info",)),
|
|
122
|
+
Cmd_type_val(("warning", "warn")),
|
|
123
|
+
Cmd_type_val(("error", "err")),
|
|
124
|
+
Cmd_type_val(("send",)),
|
|
125
|
+
Cmd_type_val(("debug",)),
|
|
126
|
+
),
|
|
86
127
|
)
|
|
87
128
|
_run_any = Cmd_type_val(
|
|
88
|
-
"$",
|
|
89
|
-
|
|
129
|
+
("$",),
|
|
130
|
+
param="<code>",
|
|
90
131
|
description=(
|
|
91
132
|
"Run code directly from the internal environment.\n"
|
|
92
133
|
"Execute the code string directly after the '$'.\n"
|
|
@@ -94,33 +135,35 @@ class Cmd_type(enum.Enum):
|
|
|
94
135
|
),
|
|
95
136
|
)
|
|
96
137
|
exit = Cmd_type_val(
|
|
97
|
-
"exit",
|
|
98
|
-
|
|
138
|
+
("exit",),
|
|
139
|
+
param="exit",
|
|
99
140
|
description="Exit this program",
|
|
100
141
|
)
|
|
101
142
|
cd = Cmd_type_val(
|
|
102
|
-
"cd",
|
|
103
|
-
|
|
143
|
+
("cd",),
|
|
144
|
+
param="<<path> | 'fd' | 'cfd'>",
|
|
104
145
|
description="Change current working directory",
|
|
146
|
+
childs=(
|
|
147
|
+
Cmd_type_val(("fd",)),
|
|
148
|
+
Cmd_type_val(("cfd",)),
|
|
149
|
+
),
|
|
105
150
|
)
|
|
106
|
-
dir = Cmd_type_val(
|
|
107
|
-
"dir",
|
|
108
|
-
opt_str="dir",
|
|
151
|
+
dir = ls = Cmd_type_val(
|
|
152
|
+
("dir", "ls"),
|
|
109
153
|
description="Print files and folders' name in the current working directory",
|
|
110
154
|
)
|
|
111
155
|
mkdir = makedir = Cmd_type_val(
|
|
112
|
-
"mkdir",
|
|
113
|
-
|
|
156
|
+
("mkdir", "makedir"),
|
|
157
|
+
param="<string>",
|
|
114
158
|
description="Create a new path",
|
|
115
159
|
)
|
|
116
160
|
cls = clear = Cmd_type_val(
|
|
117
|
-
"cls",
|
|
118
|
-
opt_str="cls / clear",
|
|
161
|
+
("cls", "clear"),
|
|
119
162
|
description="Clear screen",
|
|
120
163
|
)
|
|
121
164
|
list = Cmd_type_val(
|
|
122
|
-
"list",
|
|
123
|
-
|
|
165
|
+
("list",),
|
|
166
|
+
param="<list option>",
|
|
124
167
|
description=(
|
|
125
168
|
"Operate Ripper list\n"
|
|
126
169
|
" \n"
|
|
@@ -141,27 +184,40 @@ class Cmd_type(enum.Enum):
|
|
|
141
184
|
"<int> <int>:\n"
|
|
142
185
|
" Exchange specified index"
|
|
143
186
|
),
|
|
187
|
+
childs=(
|
|
188
|
+
Cmd_type_val(("clear", "clean")),
|
|
189
|
+
Cmd_type_val(("del", "pop")),
|
|
190
|
+
Cmd_type_val(("sort",), childs=(Cmd_type_val(("n", "r", "nr")),)),
|
|
191
|
+
),
|
|
144
192
|
)
|
|
145
193
|
run = Cmd_type_val(
|
|
146
|
-
"run",
|
|
147
|
-
|
|
194
|
+
("run",),
|
|
195
|
+
param="[<run option>] [-multithreading <0 | 1>]",
|
|
148
196
|
description=(
|
|
149
197
|
"Run the Ripper in the Ripper list\n"
|
|
150
|
-
"
|
|
198
|
+
"\n"
|
|
151
199
|
"Default:\n"
|
|
152
200
|
" Only run\n"
|
|
153
|
-
"
|
|
201
|
+
"\n"
|
|
154
202
|
"exit:\n"
|
|
155
203
|
" Close program when run finished\n"
|
|
156
|
-
"
|
|
204
|
+
"\n"
|
|
157
205
|
"shutdown [<sec>]:\n"
|
|
158
206
|
" Shutdown when run finished\n"
|
|
159
|
-
" Default: 60"
|
|
207
|
+
" Default: 60\n"
|
|
208
|
+
"\n"
|
|
209
|
+
"server [<address>]:[<port>]@[<password>]:\n"
|
|
210
|
+
" See the corresponding help for details"
|
|
211
|
+
),
|
|
212
|
+
childs=(
|
|
213
|
+
Cmd_type_val(("exit",)),
|
|
214
|
+
Cmd_type_val(("shutdown",)),
|
|
215
|
+
Cmd_type_val(("server",)),
|
|
160
216
|
),
|
|
161
217
|
)
|
|
162
218
|
server = Cmd_type_val(
|
|
163
|
-
"server",
|
|
164
|
-
|
|
219
|
+
("server",),
|
|
220
|
+
param="[<address>]:[<port>]@[<password>]",
|
|
165
221
|
description=(
|
|
166
222
|
"Boot web service\n"
|
|
167
223
|
"Default: server localhost:0\n"
|
|
@@ -169,10 +225,10 @@ class Cmd_type(enum.Enum):
|
|
|
169
225
|
),
|
|
170
226
|
)
|
|
171
227
|
config = Cmd_type_val(
|
|
172
|
-
"config",
|
|
173
|
-
|
|
228
|
+
("config",),
|
|
229
|
+
param="<config option>",
|
|
174
230
|
description=(
|
|
175
|
-
"regenerate | clear | clean
|
|
231
|
+
"regenerate | clear | clean\n"
|
|
176
232
|
" Regenerate config file\n"
|
|
177
233
|
"open\n"
|
|
178
234
|
" Open the directory where the config file is located\n"
|
|
@@ -182,23 +238,60 @@ class Cmd_type(enum.Enum):
|
|
|
182
238
|
" Set config\n"
|
|
183
239
|
" e.g. config set language zh"
|
|
184
240
|
),
|
|
241
|
+
childs=(
|
|
242
|
+
Cmd_type_val(("regenerate", "clear", "clean")),
|
|
243
|
+
Cmd_type_val(("open",)),
|
|
244
|
+
Cmd_type_val(("list",)),
|
|
245
|
+
Cmd_type_val(
|
|
246
|
+
("set",),
|
|
247
|
+
childs=tuple(Cmd_type_val((k,)) for k in Config_key._member_map_),
|
|
248
|
+
),
|
|
249
|
+
),
|
|
250
|
+
)
|
|
251
|
+
prompt = Cmd_type_val(
|
|
252
|
+
("prompt",),
|
|
253
|
+
param="<prompt option>",
|
|
254
|
+
description=(
|
|
255
|
+
"history\n" # .
|
|
256
|
+
" Show prompt history\n"
|
|
257
|
+
"clear | clean\n"
|
|
258
|
+
" Delete history file"
|
|
259
|
+
),
|
|
260
|
+
childs=(
|
|
261
|
+
Cmd_type_val(("history",)),
|
|
262
|
+
Cmd_type_val(("clear", "clean")),
|
|
263
|
+
),
|
|
185
264
|
)
|
|
186
265
|
translate = Cmd_type_val(
|
|
187
|
-
"translate",
|
|
188
|
-
|
|
266
|
+
("translate",),
|
|
267
|
+
param="<files' infix> <target lang tag> [-overwrite]",
|
|
189
268
|
description=(
|
|
190
269
|
"Translate subtitle files\n"
|
|
191
270
|
"e.g. 'translate zh-Hans zh-Hant' will translate all '*.zh-Hans.ass' files into zh-Hant"
|
|
192
271
|
),
|
|
272
|
+
childs=(Cmd_type_val(("-overwrite",)),),
|
|
193
273
|
)
|
|
194
274
|
mediainfo = Cmd_type_val(
|
|
195
|
-
"mediainfo",
|
|
196
|
-
|
|
275
|
+
("mediainfo",),
|
|
276
|
+
param="<<path> | 'fd' | 'cfd'>",
|
|
197
277
|
description="Get the media info by the Media_info class",
|
|
278
|
+
childs=(
|
|
279
|
+
Cmd_type_val(("fd",)),
|
|
280
|
+
Cmd_type_val(("cfd",)),
|
|
281
|
+
),
|
|
282
|
+
)
|
|
283
|
+
fontinfo = Cmd_type_val(
|
|
284
|
+
("fontinfo",),
|
|
285
|
+
param="<<path> | 'fd' | 'cfd'>",
|
|
286
|
+
description="Get the font info by the Font class",
|
|
287
|
+
childs=(
|
|
288
|
+
Cmd_type_val(("fd",)),
|
|
289
|
+
Cmd_type_val(("cfd",)),
|
|
290
|
+
),
|
|
198
291
|
)
|
|
199
292
|
Option = Cmd_type_val(
|
|
200
|
-
"Option",
|
|
201
|
-
|
|
293
|
+
("Option",),
|
|
294
|
+
param="...",
|
|
202
295
|
description=(
|
|
203
296
|
"-i <input> -p <preset name> [-o <output>] [-o:dir <dir>] [-pipe <vpy pathname> -crf <val> -psy-rd <val> ...] [-sub <subtitle pathname>] [-c:a <audio encoder> -b:a <audio bitrate>] [-muxer <muxer> [-r <fps>]] [-run [<run option>]] [...]\n"
|
|
204
297
|
" \n"
|
|
@@ -209,7 +302,7 @@ class Cmd_type(enum.Enum):
|
|
|
209
302
|
@classmethod
|
|
210
303
|
def from_str(cls, s: str) -> Self | None:
|
|
211
304
|
guess_str = s.replace("-", "_").replace(":", "_")
|
|
212
|
-
if guess_str in cls._member_map_
|
|
305
|
+
if guess_str in cls._member_map_:
|
|
213
306
|
return cls[guess_str]
|
|
214
307
|
return None
|
|
215
308
|
|
|
@@ -220,21 +313,25 @@ class Cmd_type(enum.Enum):
|
|
|
220
313
|
|
|
221
314
|
class Opt_type(enum.Enum):
|
|
222
315
|
_i = Cmd_type_val(
|
|
223
|
-
"-i",
|
|
224
|
-
|
|
316
|
+
("-i",),
|
|
317
|
+
param="<<path>[::<path>[?<path>...]...] | 'fd' | 'cfd'>",
|
|
225
318
|
description=(
|
|
226
319
|
"Input files' pathname or enter 'fd' to use file dialog, 'cfd' to open from the current directory\n"
|
|
227
320
|
"In some cases, it is allowed to use '?' as a delimiter to input multiple into a Ripper, for example, 'preset subset' allows multiple ASS inputs"
|
|
228
321
|
),
|
|
322
|
+
childs=(
|
|
323
|
+
Cmd_type_val(("fd",)),
|
|
324
|
+
Cmd_type_val(("cfd",)),
|
|
325
|
+
),
|
|
229
326
|
)
|
|
230
327
|
_o_dir = Cmd_type_val(
|
|
231
|
-
"-o:dir",
|
|
232
|
-
|
|
328
|
+
("-o:dir",),
|
|
329
|
+
param="<path>",
|
|
233
330
|
description="Destination directory of the output file",
|
|
234
331
|
)
|
|
235
332
|
_o = Cmd_type_val(
|
|
236
|
-
"-o",
|
|
237
|
-
|
|
333
|
+
("-o",),
|
|
334
|
+
param="<path>",
|
|
238
335
|
description=(
|
|
239
336
|
"Output file basename's prefix\n"
|
|
240
337
|
"Allow iterators and time formatting for multiple inputs\n"
|
|
@@ -242,58 +339,52 @@ class Opt_type(enum.Enum):
|
|
|
242
339
|
),
|
|
243
340
|
)
|
|
244
341
|
_auto_infix = Cmd_type_val(
|
|
245
|
-
"-auto-infix",
|
|
246
|
-
|
|
342
|
+
("-auto-infix",),
|
|
343
|
+
param="<0 | 1>",
|
|
247
344
|
description=(
|
|
248
345
|
"If enable, output file name will add auto infix:\n"
|
|
249
346
|
" no audio: '.v'\n"
|
|
250
347
|
" with audio: '.va'\n"
|
|
251
348
|
"Default: 1"
|
|
252
349
|
),
|
|
350
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
253
351
|
)
|
|
254
352
|
_preset = _p = Cmd_type_val(
|
|
255
|
-
"-preset",
|
|
256
|
-
|
|
353
|
+
("-p", "-preset"),
|
|
354
|
+
param="<string>",
|
|
257
355
|
description=(
|
|
258
356
|
"Setting preset\n"
|
|
259
|
-
"Preset name:\n"
|
|
260
|
-
"
|
|
261
|
-
" subset\n"
|
|
262
|
-
" copy\n"
|
|
263
|
-
" flac\n"
|
|
264
|
-
" x264fast x264slow\n"
|
|
265
|
-
" x265fast4 x265fast3 x265fast2 x265fast x265slow x265full\n"
|
|
266
|
-
" h264_amf h264_nvenc h264_qsv\n"
|
|
267
|
-
" hevc_amf hevc_nvenc hevc_qsv\n"
|
|
268
|
-
" av1_amf av1_nvenc av1_qsv"
|
|
357
|
+
"Preset name:\n" # .
|
|
358
|
+
f"{Preset_name.to_help_string(' ')}"
|
|
269
359
|
),
|
|
360
|
+
childs=(Cmd_type_val(tuple(Preset_name._value2member_map_)),),
|
|
270
361
|
)
|
|
271
362
|
_pipe = Cmd_type_val(
|
|
272
|
-
"-pipe",
|
|
273
|
-
|
|
363
|
+
("-pipe",),
|
|
364
|
+
param="<string>",
|
|
274
365
|
description=(
|
|
275
366
|
"Select a vpy file as pipe to input, this vpy must have input global val\n"
|
|
276
367
|
"The input in vspipe: vspipe -a input=<input> filter.vpy"
|
|
277
368
|
),
|
|
278
369
|
)
|
|
279
370
|
_pipe_gvar = Cmd_type_val(
|
|
280
|
-
"-pipe",
|
|
281
|
-
|
|
371
|
+
("-pipe:gvar",),
|
|
372
|
+
param="<key>=<val>[:...]",
|
|
282
373
|
description=(
|
|
283
374
|
"Customize the global variables passed to vspipe, and use ':' intervals for multiple variables\n"
|
|
284
375
|
' e.g. -pipe:gvar "a=1 2 3:b=abc" -> vspipe -a "a=1 2 3" -a "b=abc"'
|
|
285
376
|
),
|
|
286
377
|
)
|
|
287
378
|
_vf = Cmd_type_val(
|
|
288
|
-
"-vf",
|
|
289
|
-
|
|
379
|
+
("-vf",),
|
|
380
|
+
param="<string>",
|
|
290
381
|
description=(
|
|
291
382
|
"Customize FFmpeg's -vf\nUsing it together with -sub is undefined behavior"
|
|
292
383
|
),
|
|
293
384
|
)
|
|
294
385
|
_sub = Cmd_type_val(
|
|
295
|
-
"-sub",
|
|
296
|
-
|
|
386
|
+
("-sub",),
|
|
387
|
+
param="<<path> | 'auto' | 'auto:...'>",
|
|
297
388
|
description=(
|
|
298
389
|
"It use libass to make hard subtitle, input a subtitle pathname when you need hard subtitle\n"
|
|
299
390
|
'It can add multiple subtitles by "::"\n'
|
|
@@ -302,44 +393,51 @@ class Opt_type(enum.Enum):
|
|
|
302
393
|
"'auto:...' can only select which match infix.\n"
|
|
303
394
|
" e.g. 'auto:zh-Hans:zh-Hant'"
|
|
304
395
|
),
|
|
396
|
+
childs=(Cmd_type_val(("auto",)),),
|
|
305
397
|
)
|
|
306
398
|
_only_mux_sub_path = Cmd_type_val(
|
|
307
|
-
"-only-mux-sub-path",
|
|
308
|
-
|
|
399
|
+
("-only-mux-sub-path",),
|
|
400
|
+
param="<path>",
|
|
309
401
|
description="All subtitles and fonts in this path will be muxed",
|
|
310
402
|
)
|
|
311
403
|
_soft_sub = Cmd_type_val(
|
|
312
|
-
"-soft-sub",
|
|
313
|
-
|
|
314
|
-
description=
|
|
404
|
+
("-soft-sub",),
|
|
405
|
+
param="<<path>[?<path>...] | 'auto' | 'auto:...'>",
|
|
406
|
+
description=(
|
|
407
|
+
"Mux ASS subtitles in MKV with subset\n" # .
|
|
408
|
+
"The usage of 'auto' is detailed in '-sub'"
|
|
409
|
+
),
|
|
410
|
+
childs=(Cmd_type_val(("auto",)),),
|
|
315
411
|
)
|
|
316
412
|
_subset_font_dir = Cmd_type_val(
|
|
317
|
-
"-subset-font-dir",
|
|
318
|
-
|
|
413
|
+
("-subset-font-dir",),
|
|
414
|
+
param="<<path>[?<path>...]>",
|
|
319
415
|
description=(
|
|
320
416
|
"The fonts directory when subset\n"
|
|
321
417
|
'Default: Prioritize the current directory, followed by folders containing "font" (case-insensitive) within the current directory'
|
|
322
418
|
),
|
|
323
419
|
)
|
|
324
420
|
_subset_font_in_sub = Cmd_type_val(
|
|
325
|
-
"-subset-font-in-sub",
|
|
326
|
-
|
|
421
|
+
("-subset-font-in-sub",),
|
|
422
|
+
param="<0 | 1>",
|
|
327
423
|
description=(
|
|
328
424
|
"Encode fonts into ASS file instead of standalone files\n" # .
|
|
329
425
|
"Default: 0"
|
|
330
426
|
),
|
|
427
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
331
428
|
)
|
|
332
429
|
_subset_use_win_font = Cmd_type_val(
|
|
333
|
-
"-subset-use-win-font",
|
|
334
|
-
|
|
430
|
+
("-subset-use-win-font",),
|
|
431
|
+
param="<0 | 1>",
|
|
335
432
|
description=(
|
|
336
433
|
"Use Windows fonts when can not find font in subset-font-dir\n" # .
|
|
337
434
|
"Default: 0"
|
|
338
435
|
),
|
|
436
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
339
437
|
)
|
|
340
438
|
_subset_use_libass_spec = Cmd_type_val(
|
|
341
|
-
"-subset-use-libass-spec",
|
|
342
|
-
|
|
439
|
+
("-subset-use-libass-spec",),
|
|
440
|
+
param="<0 | 1>",
|
|
343
441
|
description=(
|
|
344
442
|
"Use libass specification when subset\n"
|
|
345
443
|
'e.g. "11\\{22}33" ->\n'
|
|
@@ -347,59 +445,61 @@ class Opt_type(enum.Enum):
|
|
|
347
445
|
' "11{22}33" (libass)\n'
|
|
348
446
|
"Default: 0"
|
|
349
447
|
),
|
|
448
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
350
449
|
)
|
|
351
450
|
_subset_drop_non_render = Cmd_type_val(
|
|
352
|
-
"-subset-drop-non-render",
|
|
353
|
-
|
|
451
|
+
("-subset-drop-non-render",),
|
|
452
|
+
param="<0 | 1>",
|
|
354
453
|
description=(
|
|
355
454
|
"Drop non rendered content such as Comment lines, Name, Effect, etc. in ASS\n"
|
|
356
455
|
"Default: 1"
|
|
357
456
|
),
|
|
457
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
358
458
|
)
|
|
359
459
|
_subset_drop_unkow_data = Cmd_type_val(
|
|
360
|
-
"-subset-drop-unkow-data",
|
|
361
|
-
|
|
460
|
+
("-subset-drop-unkow-data",),
|
|
461
|
+
param="<0 | 1>",
|
|
362
462
|
description=(
|
|
363
463
|
"Drop lines that are not in {[Script Info], [V4+ Styles], [Events]} in ASS\n"
|
|
364
464
|
"Default: 1"
|
|
365
465
|
),
|
|
466
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
366
467
|
)
|
|
367
468
|
_subset_strict = Cmd_type_val(
|
|
368
|
-
"-subset-strict",
|
|
369
|
-
|
|
469
|
+
("-subset-strict",),
|
|
470
|
+
param="<0 | 1>",
|
|
370
471
|
description=(
|
|
371
472
|
"Some error will interrupt subset\n" # .
|
|
372
473
|
"Default: 0"
|
|
373
474
|
),
|
|
475
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
374
476
|
)
|
|
375
477
|
_translate_sub = Cmd_type_val(
|
|
376
|
-
"-translate-sub",
|
|
377
|
-
|
|
478
|
+
("-translate-sub",),
|
|
479
|
+
param="<infix>:<language-tag>",
|
|
378
480
|
description=(
|
|
379
481
|
"Temporary generation of subtitle translation files\n"
|
|
380
482
|
"e.g. 'zh-Hans:zh-Hant' will temporary generation of Traditional Chinese subtitles"
|
|
381
483
|
),
|
|
382
484
|
)
|
|
383
485
|
_c_a = Cmd_type_val(
|
|
384
|
-
"-c:a",
|
|
385
|
-
|
|
486
|
+
("-c:a",),
|
|
487
|
+
param="<string>",
|
|
386
488
|
description=(
|
|
387
489
|
"Setting audio encoder\n"
|
|
388
|
-
"
|
|
389
|
-
"
|
|
390
|
-
" copy\n"
|
|
391
|
-
" libopus\n"
|
|
392
|
-
" flac"
|
|
490
|
+
"Audio encoder:\n" # .
|
|
491
|
+
f"{Audio_codec.to_help_string(' ')}"
|
|
393
492
|
),
|
|
493
|
+
childs=(Cmd_type_val(tuple(Audio_codec._value2member_map_)),),
|
|
394
494
|
)
|
|
395
495
|
_b_a = Cmd_type_val(
|
|
396
|
-
"-b:a",
|
|
397
|
-
|
|
496
|
+
("-b:a",),
|
|
497
|
+
param="<string>",
|
|
398
498
|
description="Setting audio bitrate. Default '160k'",
|
|
399
499
|
)
|
|
400
500
|
_muxer = Cmd_type_val(
|
|
401
|
-
"-muxer",
|
|
402
|
-
|
|
501
|
+
("-muxer",),
|
|
502
|
+
param="<string>",
|
|
403
503
|
description=(
|
|
404
504
|
"Setting muxer\n"
|
|
405
505
|
" \n" # .
|
|
@@ -409,24 +509,25 @@ class Opt_type(enum.Enum):
|
|
|
409
509
|
),
|
|
410
510
|
)
|
|
411
511
|
_r = _fps = Cmd_type_val(
|
|
412
|
-
"-r",
|
|
413
|
-
|
|
512
|
+
("-r", "-fps"),
|
|
513
|
+
param="<string | 'auto'>",
|
|
414
514
|
description=(
|
|
415
515
|
"Setting FPS when muxing\n"
|
|
416
516
|
"When using auto, the frame rate is automatically obtained from the input video and adsorbed to the nearest preset point"
|
|
417
517
|
),
|
|
518
|
+
childs=(Cmd_type_val(("auto",)),),
|
|
418
519
|
)
|
|
419
520
|
_chapters = Cmd_type_val(
|
|
420
|
-
"-chapters",
|
|
421
|
-
|
|
521
|
+
("-chapters",),
|
|
522
|
+
param="<path>",
|
|
422
523
|
description=(
|
|
423
524
|
"Specify the chapters file to add\n"
|
|
424
525
|
"Supports the same iteration syntax as '-o'"
|
|
425
526
|
),
|
|
426
527
|
)
|
|
427
528
|
_custom_template = _custom = _custom_format = Cmd_type_val(
|
|
428
|
-
"-custom:format",
|
|
429
|
-
|
|
529
|
+
("-custom", "-custom:format", "-custom:tempate"),
|
|
530
|
+
param="<string>",
|
|
430
531
|
description=(
|
|
431
532
|
"When -preset custom, this option will run\n"
|
|
432
533
|
"String escape: \\34/ -> \", \\39/ -> ', '' -> \"\n"
|
|
@@ -434,89 +535,106 @@ class Opt_type(enum.Enum):
|
|
|
434
535
|
),
|
|
435
536
|
)
|
|
436
537
|
_custom_suffix = Cmd_type_val(
|
|
437
|
-
"-custom:suffix",
|
|
438
|
-
|
|
538
|
+
("-custom:suffix",),
|
|
539
|
+
param="<string>",
|
|
439
540
|
description=(
|
|
440
541
|
"When -preset custom, this option will be used as a suffix for the output file\n"
|
|
441
542
|
'Default: ""'
|
|
442
543
|
),
|
|
443
544
|
)
|
|
444
545
|
_run = Cmd_type_val(
|
|
445
|
-
"-run",
|
|
446
|
-
|
|
546
|
+
("-run",),
|
|
547
|
+
param="[<string>]",
|
|
447
548
|
description=(
|
|
448
549
|
"Run the Ripper from the Ripper list\n"
|
|
449
|
-
"
|
|
550
|
+
"\n"
|
|
450
551
|
"Default:\n"
|
|
451
552
|
" Only run\n"
|
|
452
|
-
"
|
|
553
|
+
"\n"
|
|
453
554
|
"exit:\n"
|
|
454
555
|
" Close program when run finished\n"
|
|
455
|
-
"
|
|
556
|
+
"\n"
|
|
456
557
|
"shutdown [<sec>]:\n"
|
|
457
558
|
" Shutdown when run finished\n"
|
|
458
559
|
" Default: 60\n"
|
|
560
|
+
"\n"
|
|
561
|
+
"server [<address>]:[<port>]@[<password>]:\n"
|
|
562
|
+
" See the corresponding help for details"
|
|
563
|
+
),
|
|
564
|
+
childs=(
|
|
565
|
+
Cmd_type_val(("exit",)),
|
|
566
|
+
Cmd_type_val(("shutdown",)),
|
|
567
|
+
Cmd_type_val(("server",)),
|
|
459
568
|
),
|
|
460
569
|
)
|
|
461
570
|
_ff_params_ff = _ff_params = Cmd_type_val(
|
|
462
|
-
"-ff-params:ff",
|
|
463
|
-
|
|
571
|
+
("-ff-params", "-ff-params:ff"),
|
|
572
|
+
param="<string>",
|
|
464
573
|
description=(
|
|
465
574
|
"Set FFmpeg global options\n" # .
|
|
466
575
|
"Same as ffmpeg <option> ... -i ..."
|
|
467
576
|
),
|
|
468
577
|
)
|
|
469
578
|
_ff_params_in = Cmd_type_val(
|
|
470
|
-
"-ff-params:in",
|
|
471
|
-
|
|
579
|
+
("-ff-params:in",),
|
|
580
|
+
param="<string>",
|
|
472
581
|
description=(
|
|
473
582
|
"Set FFmpeg input options\n" # .
|
|
474
583
|
"Same as ffmpeg ... <option> -i ..."
|
|
475
584
|
),
|
|
476
585
|
)
|
|
477
586
|
_ff_params_out = Cmd_type_val(
|
|
478
|
-
"-ff-params:out",
|
|
479
|
-
|
|
587
|
+
("-ff-params:out",),
|
|
588
|
+
param="<string>",
|
|
480
589
|
description=(
|
|
481
590
|
"Set FFmpeg output options\n" # .
|
|
482
591
|
"Same as ffmpeg -i ... <option> ..."
|
|
483
592
|
),
|
|
484
593
|
)
|
|
485
594
|
_hwaccel = Cmd_type_val(
|
|
486
|
-
"-hwaccel",
|
|
487
|
-
|
|
595
|
+
("-hwaccel",),
|
|
596
|
+
param="<string>",
|
|
488
597
|
description="Use FFmpeg hwaccel (See 'ffmpeg -hwaccels' for details)",
|
|
489
598
|
)
|
|
490
599
|
_ss = Cmd_type_val(
|
|
491
|
-
"-ss",
|
|
492
|
-
|
|
600
|
+
("-ss",),
|
|
601
|
+
param="<time>",
|
|
493
602
|
description=(
|
|
494
603
|
"Set FFmpeg input file start time\n" # .
|
|
495
604
|
"Same as ffmpeg -ss <time> -i ..."
|
|
496
605
|
),
|
|
497
606
|
)
|
|
498
607
|
_t = Cmd_type_val(
|
|
499
|
-
"-t",
|
|
500
|
-
|
|
608
|
+
("-t",),
|
|
609
|
+
param="<time>",
|
|
501
610
|
description=(
|
|
502
611
|
"Set FFmpeg output file duration\n" # .
|
|
503
612
|
"Same as ffmpeg -i ... -t <time> ..."
|
|
504
613
|
),
|
|
505
614
|
)
|
|
506
615
|
_hevc_strict = Cmd_type_val(
|
|
507
|
-
"-hevc-strict",
|
|
508
|
-
|
|
616
|
+
("-hevc-strict",),
|
|
617
|
+
param="<0 | 1>",
|
|
509
618
|
description=(
|
|
510
|
-
"
|
|
511
|
-
"When the resolution >= 4k, close HME\n"
|
|
619
|
+
"When the resolution >= 4K, close HME, and auto reduce the -ref\n" # .
|
|
512
620
|
"Default: 1"
|
|
513
621
|
),
|
|
622
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
623
|
+
)
|
|
624
|
+
_multithreading = Cmd_type_val(
|
|
625
|
+
("-multithreading",),
|
|
626
|
+
param="<0 | 1>",
|
|
627
|
+
description=(
|
|
628
|
+
"Use multi-threading to run Ripper list, suitable for situations with low performance occupancy\n"
|
|
629
|
+
"e.g. -p subset or -p copy"
|
|
630
|
+
),
|
|
631
|
+
childs=(Cmd_type_val(("0", "1")),),
|
|
514
632
|
)
|
|
515
633
|
|
|
516
634
|
@classmethod
|
|
517
635
|
def from_str(cls, s: str) -> Self | None:
|
|
518
636
|
guess_str = s.replace("-", "_").replace(":", "_")
|
|
519
|
-
if guess_str in cls._member_map_
|
|
637
|
+
if guess_str in cls._member_map_:
|
|
520
638
|
return cls[guess_str]
|
|
521
639
|
return None
|
|
522
640
|
|
|
@@ -525,6 +643,11 @@ class Opt_type(enum.Enum):
|
|
|
525
643
|
return "\n\n".join(ct.value.to_doc() for ct in cls)
|
|
526
644
|
|
|
527
645
|
|
|
646
|
+
Cmd_type.help.value.childs = tuple(
|
|
647
|
+
ct.value for ct in itertools.chain(Cmd_type, Opt_type) if ct is not Cmd_type.help
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
|
|
528
651
|
def get_help_doc() -> str:
|
|
529
652
|
from .easyrip_mlang import gettext
|
|
530
653
|
|
|
@@ -534,15 +657,201 @@ def get_help_doc() -> str:
|
|
|
534
657
|
"\n"
|
|
535
658
|
f"{gettext('Help')}:\n"
|
|
536
659
|
"\n"
|
|
537
|
-
f"
|
|
660
|
+
f"{textwrap.indent(gettext("Enter '<cmd> [<param> ...]' to execute Easy Rip commands or any commands that exist in environment.\nOr enter '<option> <param> [<option> <param> ...]' to add Ripper."), ' ')}\n"
|
|
538
661
|
"\n"
|
|
539
662
|
"\n"
|
|
540
|
-
f"{gettext('Commands')}:\n"
|
|
663
|
+
f"{gettext('Easy Rip Commands')}:\n"
|
|
541
664
|
"\n"
|
|
542
|
-
f"{textwrap.indent(Cmd_type.to_doc(), ' ')}"
|
|
665
|
+
f"{textwrap.indent(Cmd_type.to_doc(), ' ')}\n"
|
|
543
666
|
"\n"
|
|
544
667
|
"\n"
|
|
545
668
|
f"{gettext('Ripper options')}:\n"
|
|
546
669
|
"\n"
|
|
547
670
|
f"{textwrap.indent(Opt_type.to_doc(), ' ')}"
|
|
548
671
|
)
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
type nested_dict = dict[str, "nested_dict | Completer"]
|
|
675
|
+
META_DICT_OPT_TYPE = {
|
|
676
|
+
name: lambda opt=opt: opt.value.param
|
|
677
|
+
for opt in Opt_type
|
|
678
|
+
for name in opt.value.names
|
|
679
|
+
}
|
|
680
|
+
META_DICT_CMD_TYPE = {
|
|
681
|
+
name: lambda opt=opt: opt.value.param
|
|
682
|
+
for opt in Cmd_type
|
|
683
|
+
for name in opt.value.names
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
def _nested_dict_to_nc(n_dict: nested_dict) -> NestedCompleter:
|
|
688
|
+
return NestedCompleter(
|
|
689
|
+
{
|
|
690
|
+
k: (v if isinstance(v, Completer) else _nested_dict_to_nc(v) if v else None)
|
|
691
|
+
for k, v in n_dict.items()
|
|
692
|
+
}
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
class CmdCompleter(NestedCompleter):
|
|
697
|
+
def get_completions(
|
|
698
|
+
self, document: Document, complete_event: CompleteEvent
|
|
699
|
+
) -> Iterable[Completion]:
|
|
700
|
+
# Split document.
|
|
701
|
+
text = document.text_before_cursor.lstrip()
|
|
702
|
+
words = text.split()
|
|
703
|
+
stripped_len = len(document.text_before_cursor) - len(text)
|
|
704
|
+
|
|
705
|
+
# If there is a space, check for the first term, and use a
|
|
706
|
+
# subcompleter.
|
|
707
|
+
if " " in text:
|
|
708
|
+
first_term = text.split()[0]
|
|
709
|
+
completer = self.options.get(first_term)
|
|
710
|
+
|
|
711
|
+
# If we have a sub completer, use this for the completions.
|
|
712
|
+
if completer is not None:
|
|
713
|
+
remaining_text = text[len(first_term) :].lstrip()
|
|
714
|
+
move_cursor = len(text) - len(remaining_text) + stripped_len
|
|
715
|
+
|
|
716
|
+
new_document = Document(
|
|
717
|
+
remaining_text,
|
|
718
|
+
cursor_position=document.cursor_position - move_cursor,
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
yield from completer.get_completions(new_document, complete_event)
|
|
722
|
+
|
|
723
|
+
elif words and (_cmd := Cmd_type.from_str(words[-1])) is not None:
|
|
724
|
+
yield from (
|
|
725
|
+
Completion(
|
|
726
|
+
text=words[-1],
|
|
727
|
+
start_position=-len(words[-1]),
|
|
728
|
+
display_meta=META_DICT_CMD_TYPE.get(words[-1], ""),
|
|
729
|
+
),
|
|
730
|
+
Completion(
|
|
731
|
+
text="",
|
|
732
|
+
display="✔",
|
|
733
|
+
display_meta=(
|
|
734
|
+
f"{_desc_list[0]}..."
|
|
735
|
+
if len(_desc_list := _cmd.value.description.split("\n")) > 1
|
|
736
|
+
else _desc_list[0]
|
|
737
|
+
),
|
|
738
|
+
),
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
# No space in the input: behave exactly like `WordCompleter`.
|
|
742
|
+
else:
|
|
743
|
+
# custom
|
|
744
|
+
completer = FuzzyWordCompleter(
|
|
745
|
+
tuple(self.options),
|
|
746
|
+
meta_dict=META_DICT_CMD_TYPE, # pyright: ignore[reportArgumentType]
|
|
747
|
+
WORD=True,
|
|
748
|
+
)
|
|
749
|
+
yield from completer.get_completions(document, complete_event)
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
class OptCompleter(Completer):
|
|
753
|
+
def __init__(self, *, opt_tree: nested_dict) -> None:
|
|
754
|
+
self.opt_tree: Final[nested_dict] = opt_tree
|
|
755
|
+
|
|
756
|
+
def get_completions(
|
|
757
|
+
self, document: Document, complete_event: CompleteEvent
|
|
758
|
+
) -> Iterable[Completion]:
|
|
759
|
+
text = document.text_before_cursor.lstrip()
|
|
760
|
+
|
|
761
|
+
words = text.split()
|
|
762
|
+
|
|
763
|
+
if len(words) >= 1 and not text.startswith("-"):
|
|
764
|
+
return
|
|
765
|
+
|
|
766
|
+
opt_tree_pos_list: list[nested_dict | Completer] = [self.opt_tree]
|
|
767
|
+
|
|
768
|
+
for word in words:
|
|
769
|
+
if isinstance(opt_tree_pos_list[-1], Completer):
|
|
770
|
+
opt_tree_pos_list.append(self.opt_tree.get(word, self.opt_tree))
|
|
771
|
+
else:
|
|
772
|
+
opt_tree_pos_list.append(
|
|
773
|
+
opt_tree_pos_list[-1].get(
|
|
774
|
+
word, self.opt_tree.get(word, self.opt_tree)
|
|
775
|
+
)
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
if opt_tree_pos_list[-1] is not self.opt_tree and not text.endswith(" "):
|
|
779
|
+
yield from (
|
|
780
|
+
Completion(
|
|
781
|
+
text=words[-1],
|
|
782
|
+
start_position=-len(words[-1]),
|
|
783
|
+
display_meta=META_DICT_OPT_TYPE.get(words[-1], ""),
|
|
784
|
+
),
|
|
785
|
+
Completion(
|
|
786
|
+
text="",
|
|
787
|
+
display="✔",
|
|
788
|
+
display_meta=(
|
|
789
|
+
""
|
|
790
|
+
if (_opt := Opt_type.from_str(text)) is None
|
|
791
|
+
else f"{_desc_list[0]}..."
|
|
792
|
+
if len(_desc_list := _opt.value.description.split("\n")) > 1
|
|
793
|
+
else _desc_list[0]
|
|
794
|
+
),
|
|
795
|
+
),
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
elif isinstance(opt_tree_pos_list[-1], Completer):
|
|
799
|
+
# 直接使用 PathCompleter 会因为上下文问题失效,所以将上文套进 NestedCompleter
|
|
800
|
+
new_nd: nested_dict = {}
|
|
801
|
+
new_nd_pos: nested_dict = new_nd
|
|
802
|
+
for word in words[:-1]:
|
|
803
|
+
new_nd_pos[word] = new_nd_pos = {}
|
|
804
|
+
new_nd_pos[words[-1]] = opt_tree_pos_list[-1]
|
|
805
|
+
|
|
806
|
+
yield from _nested_dict_to_nc(new_nd).get_completions(
|
|
807
|
+
document=document, complete_event=complete_event
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
elif len(words) >= 2 and isinstance(opt_tree_pos_list[-2], Completer):
|
|
811
|
+
new_nd: nested_dict = {}
|
|
812
|
+
new_nd_pos: nested_dict = new_nd
|
|
813
|
+
for word in words[:-2]:
|
|
814
|
+
new_nd_pos[word] = new_nd_pos = {}
|
|
815
|
+
new_nd_pos[words[-2]] = opt_tree_pos_list[-2]
|
|
816
|
+
|
|
817
|
+
yield from merge_completers(
|
|
818
|
+
(
|
|
819
|
+
DeduplicateCompleter(
|
|
820
|
+
merge_completers(
|
|
821
|
+
(
|
|
822
|
+
_nested_dict_to_nc(new_nd),
|
|
823
|
+
FuzzyCompleter(_nested_dict_to_nc(new_nd), WORD=True),
|
|
824
|
+
)
|
|
825
|
+
)
|
|
826
|
+
),
|
|
827
|
+
FuzzyCompleter(
|
|
828
|
+
WordCompleter(
|
|
829
|
+
words=tuple(opt_tree_pos_list[-1]),
|
|
830
|
+
meta_dict=META_DICT_OPT_TYPE,
|
|
831
|
+
WORD=True, # 匹配标点
|
|
832
|
+
match_middle=True,
|
|
833
|
+
),
|
|
834
|
+
WORD=False,
|
|
835
|
+
),
|
|
836
|
+
)
|
|
837
|
+
).get_completions(document=document, complete_event=complete_event)
|
|
838
|
+
|
|
839
|
+
else:
|
|
840
|
+
yield from FuzzyCompleter(
|
|
841
|
+
WordCompleter(
|
|
842
|
+
words=tuple(
|
|
843
|
+
opt_tree_pos_list[-1]
|
|
844
|
+
| (
|
|
845
|
+
{}
|
|
846
|
+
if text.endswith(" ")
|
|
847
|
+
or len(words) <= 1
|
|
848
|
+
or isinstance(opt_tree_pos_list[-2], Completer)
|
|
849
|
+
else opt_tree_pos_list[-2]
|
|
850
|
+
)
|
|
851
|
+
),
|
|
852
|
+
meta_dict=META_DICT_OPT_TYPE,
|
|
853
|
+
WORD=True, # 匹配标点
|
|
854
|
+
match_middle=True,
|
|
855
|
+
),
|
|
856
|
+
WORD=not text.endswith(" "),
|
|
857
|
+
).get_completions(document=document, complete_event=complete_event)
|