easyrip 4.3.3__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 CHANGED
@@ -14,10 +14,13 @@ from .easyrip_mlang import (
14
14
  Lang_tag_region,
15
15
  Lang_tag_script,
16
16
  )
17
- from .ripper import Ass, Media_info, Ripper
17
+ from .ripper.media_info import Media_info
18
+ from .ripper.ripper import Ripper
19
+ from .ripper.sub_and_font import Ass, Font, load_fonts
18
20
 
19
21
  __all__ = [
20
22
  "Ass",
23
+ "Font",
21
24
  "Global_lang_val",
22
25
  "Lang_tag",
23
26
  "Lang_tag_language",
@@ -30,6 +33,7 @@ __all__ = [
30
33
  "gettext",
31
34
  "global_val",
32
35
  "init",
36
+ "load_fonts",
33
37
  "log",
34
38
  "run_command",
35
39
  ]
easyrip/__main__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import sys
2
- from collections.abc import Iterable
3
- from typing import NoReturn
2
+ from collections.abc import Coroutine, Iterable
3
+ from typing import Any, NoReturn
4
4
 
5
5
  import Crypto
6
6
  import fontTools
@@ -8,7 +8,9 @@ import prompt_toolkit
8
8
  from prompt_toolkit import ANSI, prompt
9
9
  from prompt_toolkit.completion import merge_completers
10
10
  from prompt_toolkit.history import InMemoryHistory
11
+ from prompt_toolkit.input.ansi_escape_sequences import ANSI_SEQUENCES
11
12
  from prompt_toolkit.key_binding import KeyBindings, KeyPressEvent
13
+ from prompt_toolkit.key_binding.bindings import named_commands
12
14
  from prompt_toolkit.keys import Keys
13
15
 
14
16
  from .easyrip_command import (
@@ -48,6 +50,14 @@ def run() -> NoReturn:
48
50
  def _(event: KeyPressEvent) -> None:
49
51
  event.app.current_buffer.insert_text(C_D)
50
52
 
53
+ ANSI_SEQUENCES["\x08"] = Keys.F24
54
+
55
+ @key_bindings.add(Keys.F24)
56
+ def _(
57
+ event: KeyPressEvent,
58
+ ) -> object | Coroutine[Any, Any, object]:
59
+ return named_commands.get_by_name("unix-word-rubout").handler(event)
60
+
51
61
  path_completer = SmartPathCompleter()
52
62
 
53
63
  def _ctv_to_nc(ctvs: Iterable[Cmd_type_val]) -> CmdCompleter:
@@ -64,6 +74,7 @@ def run() -> NoReturn:
64
74
  in {
65
75
  *Cmd_type.cd.value.names,
66
76
  *Cmd_type.mediainfo.value.names,
77
+ *Cmd_type.fontinfo.value.names,
67
78
  }
68
79
  else ()
69
80
  ),
@@ -102,7 +113,7 @@ def run() -> NoReturn:
102
113
  cmd_ctv_tuple = tuple(ct.value for ct in Cmd_type if ct != Cmd_type.Option)
103
114
  prompt_history = (
104
115
  ConfigFileHistory(easyrip_prompt.PROMPT_HISTORY_FILE)
105
- if config.get_user_profile(Config_key.prompt_history_save_file)
116
+ if config.get_user_profile(Config_key.save_prompt_history)
106
117
  else InMemoryHistory()
107
118
  )
108
119
 
@@ -128,8 +139,11 @@ def run() -> NoReturn:
128
139
  log.debug("Manually force exit")
129
140
  sys.exit(0)
130
141
 
131
- if not run_command(command):
132
- log.warning("Stop run command")
142
+ try:
143
+ if not run_command(command):
144
+ log.warning("Stop run command")
145
+ except KeyboardInterrupt:
146
+ log.warning("Manually stop run command")
133
147
 
134
148
 
135
149
  if __name__ == "__main__":
@@ -19,6 +19,7 @@ from prompt_toolkit.document import Document
19
19
 
20
20
  from . import global_val
21
21
  from .easyrip_config.config_key import Config_key
22
+ from .ripper.param import Audio_codec, Preset_name
22
23
 
23
24
 
24
25
  @final
@@ -243,7 +244,7 @@ class Cmd_type(enum.Enum):
243
244
  Cmd_type_val(("list",)),
244
245
  Cmd_type_val(
245
246
  ("set",),
246
- childs=tuple(Cmd_type_val((k,)) for k in Config_key._value2member_map_),
247
+ childs=tuple(Cmd_type_val((k,)) for k in Config_key._member_map_),
247
248
  ),
248
249
  ),
249
250
  )
@@ -279,6 +280,15 @@ class Cmd_type(enum.Enum):
279
280
  Cmd_type_val(("cfd",)),
280
281
  ),
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
+ ),
291
+ )
282
292
  Option = Cmd_type_val(
283
293
  ("Option",),
284
294
  param="...",
@@ -344,48 +354,10 @@ class Opt_type(enum.Enum):
344
354
  param="<string>",
345
355
  description=(
346
356
  "Setting preset\n"
347
- "Preset name:\n"
348
- " custom\n"
349
- " subset\n"
350
- " copy\n"
351
- " flac\n"
352
- " x264fast x264slow\n"
353
- " x265fast4 x265fast3 x265fast2 x265fast x265slow x265full\n"
354
- " svtav1\n"
355
- " vvenc\n"
356
- " h264_qsv h264_nvenc h264_amf\n"
357
- " hevc_qsv hevc_nvenc hevc_amf\n"
358
- " av1_qsv av1_nvenc av1_amf"
359
- ),
360
- childs=(
361
- Cmd_type_val(
362
- (
363
- "custom",
364
- "subset",
365
- "copy",
366
- "flac",
367
- "x264fast",
368
- "x264slow",
369
- "x265fast4",
370
- "x265fast3",
371
- "x265fast2",
372
- "x265fast",
373
- "x265slow",
374
- "x265full",
375
- "svtav1",
376
- "vvenc",
377
- "h264_qsv",
378
- "h264_nvenc",
379
- "h264_amf",
380
- "hevc_qsv",
381
- "hevc_nvenc",
382
- "hevc_amf",
383
- "av1_qsv",
384
- "av1_nvenc",
385
- "av1_amf",
386
- )
387
- ),
357
+ "Preset name:\n" # .
358
+ f"{Preset_name.to_help_string(' ')}"
388
359
  ),
360
+ childs=(Cmd_type_val(tuple(Preset_name._value2member_map_)),),
389
361
  )
390
362
  _pipe = Cmd_type_val(
391
363
  ("-pipe",),
@@ -421,7 +393,7 @@ class Opt_type(enum.Enum):
421
393
  "'auto:...' can only select which match infix.\n"
422
394
  " e.g. 'auto:zh-Hans:zh-Hant'"
423
395
  ),
424
- childs=(Cmd_type_val(("atuo",)),),
396
+ childs=(Cmd_type_val(("auto",)),),
425
397
  )
426
398
  _only_mux_sub_path = Cmd_type_val(
427
399
  ("-only-mux-sub-path",),
@@ -435,7 +407,7 @@ class Opt_type(enum.Enum):
435
407
  "Mux ASS subtitles in MKV with subset\n" # .
436
408
  "The usage of 'auto' is detailed in '-sub'"
437
409
  ),
438
- childs=(Cmd_type_val(("atuo",)),),
410
+ childs=(Cmd_type_val(("auto",)),),
439
411
  )
440
412
  _subset_font_dir = Cmd_type_val(
441
413
  ("-subset-font-dir",),
@@ -515,13 +487,10 @@ class Opt_type(enum.Enum):
515
487
  param="<string>",
516
488
  description=(
517
489
  "Setting audio encoder\n"
518
- " \n" # .
519
- "Audio encoder:\n"
520
- " copy\n"
521
- " libopus\n"
522
- " flac"
490
+ "Audio encoder:\n" # .
491
+ f"{Audio_codec.to_help_string(' ')}"
523
492
  ),
524
- childs=(Cmd_type_val(("copy", "libopus", "flac")),),
493
+ childs=(Cmd_type_val(tuple(Audio_codec._value2member_map_)),),
525
494
  )
526
495
  _b_a = Cmd_type_val(
527
496
  ("-b:a",),
@@ -546,7 +515,7 @@ class Opt_type(enum.Enum):
546
515
  "Setting FPS when muxing\n"
547
516
  "When using auto, the frame rate is automatically obtained from the input video and adsorbed to the nearest preset point"
548
517
  ),
549
- childs=(Cmd_type_val(("atuo",)),),
518
+ childs=(Cmd_type_val(("auto",)),),
550
519
  )
551
520
  _chapters = Cmd_type_val(
552
521
  ("-chapters",),
@@ -1,23 +1,30 @@
1
1
  import json
2
2
  import os
3
3
  from pathlib import Path
4
+ from typing import Literal, get_origin, overload
4
5
 
5
6
  from ..easyrip_log import log
6
7
  from ..easyrip_mlang import all_supported_lang_map, gettext
7
8
  from ..global_val import CONFIG_DIR
8
- from .config_key import CONFIG_VERSION, Config_key
9
+ from ..utils import type_match
10
+ from .config_key import CONFIG_TYPE_DICT, CONFIG_VERSION, Config_key
9
11
 
10
- CONFIG_DEFAULT_DICT: dict[Config_key, str | bool] = {
12
+ CONFIG_DEFAULT_DICT: dict[Config_key, str | bool | list[str]] = {
11
13
  Config_key.language: "auto",
12
14
  Config_key.check_update: True,
13
15
  Config_key.check_dependent: True,
14
- Config_key.startup_directory: "",
16
+ Config_key.startup_dir: "",
17
+ Config_key.startup_dir_blacklist: [],
15
18
  Config_key.force_log_file_path: "",
16
19
  Config_key.log_print_level: log.LogLevel.send.name,
17
20
  Config_key.log_write_level: log.LogLevel.send.name,
18
- Config_key.prompt_history_save_file: True,
21
+ Config_key.save_prompt_history: True,
19
22
  }
20
23
 
24
+ assert all(k in CONFIG_DEFAULT_DICT for k in Config_key), [
25
+ k.name for k in Config_key if k not in CONFIG_DEFAULT_DICT
26
+ ]
27
+
21
28
 
22
29
  class config:
23
30
  _config_dir: Path
@@ -32,8 +39,8 @@ class config:
32
39
  if not cls._config_file.is_file():
33
40
  cls._config_dir.mkdir(exist_ok=True)
34
41
  with cls._config_file.open("wt", encoding="utf-8", newline="\n") as f:
35
- config_default_dict: dict[str, str | bool] = {
36
- k.value: v for k, v in CONFIG_DEFAULT_DICT.items()
42
+ config_default_dict: dict[str, str | bool | list[str]] = {
43
+ k.name: v for k, v in CONFIG_DEFAULT_DICT.items()
37
44
  }
38
45
  json.dump(
39
46
  {
@@ -104,7 +111,11 @@ class config:
104
111
  return True
105
112
 
106
113
  @classmethod
107
- def set_user_profile(cls, key: str, val: str | int | float | bool) -> bool:
114
+ def set_user_profile(
115
+ cls,
116
+ key: str,
117
+ val: str | bool | list[str],
118
+ ) -> bool:
108
119
  if cls._config is None and not cls._read_config():
109
120
  return False
110
121
 
@@ -113,21 +124,71 @@ class config:
113
124
  return False
114
125
 
115
126
  if "user_profile" not in cls._config:
116
- log.error("User profile is not found in config")
127
+ log.error("User profile is not found in config file")
117
128
  return False
118
129
 
119
- if key in Config_key:
130
+ if key in Config_key._member_map_:
131
+ need_type = CONFIG_TYPE_DICT[Config_key[key]]
132
+ if not type_match(val, need_type):
133
+ log.error(
134
+ "Type mismatch: need '{}'",
135
+ need_type if get_origin(need_type) else need_type.__name__,
136
+ )
137
+ return False
120
138
  cls._config["user_profile"][key] = val
121
139
  else:
122
140
  log.error("Key '{}' is not found in user profile", key)
123
141
  return False
124
142
  return cls._write_config()
125
143
 
144
+ @overload
145
+ @classmethod
146
+ def get_user_profile(
147
+ cls,
148
+ config_key: Literal[
149
+ Config_key.language,
150
+ Config_key.startup_dir,
151
+ Config_key.force_log_file_path,
152
+ Config_key.log_print_level,
153
+ Config_key.log_write_level,
154
+ ],
155
+ ) -> str | None: ...
156
+
157
+ @overload
158
+ @classmethod
159
+ def get_user_profile(
160
+ cls,
161
+ config_key: Literal[
162
+ Config_key.check_update,
163
+ Config_key.check_dependent,
164
+ Config_key.save_prompt_history,
165
+ ],
166
+ ) -> bool | None: ...
167
+
168
+ @overload
126
169
  @classmethod
127
170
  def get_user_profile(
128
- cls, config_key: Config_key | str
129
- ) -> str | int | float | bool | None:
130
- key = config_key.value if isinstance(config_key, Config_key) else config_key
171
+ cls,
172
+ config_key: Literal[Config_key.startup_dir_blacklist],
173
+ ) -> list[str] | None: ...
174
+
175
+ @overload
176
+ @classmethod
177
+ def get_user_profile(
178
+ cls,
179
+ config_key: str,
180
+ ) -> str | bool | list[str] | None: ...
181
+
182
+ @classmethod
183
+ def get_user_profile(
184
+ cls,
185
+ config_key: Config_key | str,
186
+ ) -> str | bool | list[str] | None:
187
+ key = config_key.name if isinstance(config_key, Config_key) else config_key
188
+
189
+ if key not in Config_key._member_map_:
190
+ log.error("The key '{}' is not a config", key)
191
+ return None
131
192
 
132
193
  if cls._config is None:
133
194
  cls._read_config()
@@ -161,43 +222,47 @@ class config:
161
222
  def _get_config_about(cls, key: str) -> str:
162
223
  return (
163
224
  {
164
- Config_key.language.value: gettext(
225
+ Config_key.language.name: gettext(
165
226
  "Easy Rip's language, support incomplete matching. Default: {}. Supported: {}",
166
227
  CONFIG_DEFAULT_DICT[Config_key.language],
167
228
  ", ".join(("auto", *(str(tag) for tag in all_supported_lang_map))),
168
229
  ),
169
- Config_key.check_update.value: gettext(
230
+ Config_key.check_update.name: gettext(
170
231
  "Auto check the update of Easy Rip. Default: {}",
171
232
  CONFIG_DEFAULT_DICT[Config_key.check_update],
172
233
  ),
173
- Config_key.check_dependent.value: gettext(
234
+ Config_key.check_dependent.name: gettext(
174
235
  "Auto check the versions of all dependent programs. Default: {}",
175
236
  CONFIG_DEFAULT_DICT[Config_key.check_dependent],
176
237
  ),
177
- Config_key.startup_directory.value: gettext(
238
+ Config_key.startup_dir.name: gettext(
178
239
  "Program startup directory, when the value is empty, starts in the working directory. Default: {}",
179
- CONFIG_DEFAULT_DICT[Config_key.startup_directory] or '""',
240
+ CONFIG_DEFAULT_DICT[Config_key.startup_dir] or '""',
241
+ ),
242
+ Config_key.startup_dir_blacklist.name: gettext(
243
+ "Directory list. When the startup directory is a blacklisted directory, rollback to startup directory. Default: {}",
244
+ CONFIG_DEFAULT_DICT[Config_key.startup_dir] or '""',
180
245
  ),
181
- Config_key.force_log_file_path.value: gettext(
246
+ Config_key.force_log_file_path.name: gettext(
182
247
  "Force change of log file path, when the value is empty, it is the working directory. Default: {}",
183
248
  CONFIG_DEFAULT_DICT[Config_key.force_log_file_path] or '""',
184
249
  ),
185
- Config_key.log_print_level.value: gettext(
250
+ Config_key.log_print_level.name: gettext(
186
251
  "Logs this level and above will be printed, and if the value is '{}', they will not be printed. Default: {}. Supported: {}",
187
252
  log.LogLevel.none.name,
188
253
  CONFIG_DEFAULT_DICT[Config_key.log_print_level],
189
254
  ", ".join(log.LogLevel._member_names_),
190
255
  ),
191
- Config_key.log_write_level.value: gettext(
256
+ Config_key.log_write_level.name: gettext(
192
257
  "Logs this level and above will be written, and if the value is '{}', the '{}' only be written when 'server', they will not be written. Default: {}. Supported: {}",
193
258
  log.LogLevel.none.name,
194
259
  log.LogLevel.send.name,
195
260
  CONFIG_DEFAULT_DICT[Config_key.log_write_level],
196
261
  ", ".join(log.LogLevel._member_names_),
197
262
  ),
198
- Config_key.prompt_history_save_file.value: gettext(
263
+ Config_key.save_prompt_history.name: gettext(
199
264
  "Save prompt history to config directory, otherwise save to memory. Take effect after reboot. Default: {}",
200
- CONFIG_DEFAULT_DICT[Config_key.prompt_history_save_file],
265
+ CONFIG_DEFAULT_DICT[Config_key.save_prompt_history],
201
266
  ),
202
267
  }
203
268
  | (cls._config or {})
@@ -1,14 +1,28 @@
1
1
  import enum
2
2
 
3
- CONFIG_VERSION = "4.2.0"
3
+ CONFIG_VERSION = "4.6.0"
4
4
 
5
5
 
6
6
  class Config_key(enum.Enum):
7
- language = "language"
8
- check_update = "check_update"
9
- check_dependent = "check_dependent"
10
- startup_directory = "startup_directory"
11
- force_log_file_path = "force_log_file_path"
12
- log_print_level = "log_print_level"
13
- log_write_level = "log_write_level"
14
- prompt_history_save_file = "prompt_history_file"
7
+ language = enum.auto()
8
+ check_update = enum.auto()
9
+ check_dependent = enum.auto()
10
+ startup_dir = enum.auto()
11
+ startup_dir_blacklist = enum.auto()
12
+ force_log_file_path = enum.auto()
13
+ log_print_level = enum.auto()
14
+ log_write_level = enum.auto()
15
+ save_prompt_history = enum.auto()
16
+
17
+
18
+ CONFIG_TYPE_DICT: dict[Config_key, type] = {
19
+ Config_key.language: str,
20
+ Config_key.check_update: bool,
21
+ Config_key.check_dependent: bool,
22
+ Config_key.startup_dir: str,
23
+ Config_key.startup_dir_blacklist: list[str],
24
+ Config_key.force_log_file_path: str,
25
+ Config_key.log_print_level: str,
26
+ Config_key.log_write_level: str,
27
+ Config_key.save_prompt_history: bool,
28
+ }
easyrip/easyrip_log.py CHANGED
@@ -106,7 +106,7 @@ class log:
106
106
  only_print = enum.auto()
107
107
  only_write = enum.auto()
108
108
 
109
- html_filename: str = "encoding_log.html" # 在调用前覆写
109
+ html_filename: str = "EasyRip_log.html" # 在调用前覆写
110
110
  print_level: LogLevel = LogLevel.send
111
111
  write_level: LogLevel = LogLevel.send
112
112