easyrip 4.1.0__tar.gz → 4.3.0__tar.gz

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.
Files changed (39) hide show
  1. {easyrip-4.1.0 → easyrip-4.3.0}/PKG-INFO +16 -34
  2. easyrip-4.3.0/README.md +65 -0
  3. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/__main__.py +20 -8
  4. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_command.py +75 -27
  5. easyrip-4.1.0/easyrip/easyrip_config.py → easyrip-4.3.0/easyrip/easyrip_config/config.py +16 -33
  6. easyrip-4.3.0/easyrip/easyrip_config/config_key.py +14 -0
  7. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_main.py +107 -60
  8. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_mlang/lang_zh_Hans_CN.py +18 -10
  9. easyrip-4.3.0/easyrip/easyrip_prompt.py +17 -0
  10. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_web/http_server.py +17 -1
  11. easyrip-4.3.0/easyrip/global_val.py +25 -0
  12. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip.egg-info/PKG-INFO +16 -34
  13. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip.egg-info/SOURCES.txt +4 -2
  14. easyrip-4.3.0/pyproject.toml +50 -0
  15. easyrip-4.1.0/README.md +0 -79
  16. easyrip-4.1.0/easyrip/global_val.py +0 -5
  17. easyrip-4.1.0/setup.py +0 -61
  18. {easyrip-4.1.0 → easyrip-4.3.0}/LICENSE +0 -0
  19. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/__init__.py +0 -0
  20. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_log.py +0 -0
  21. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_mlang/__init__.py +0 -0
  22. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_mlang/global_lang_val.py +0 -0
  23. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_mlang/lang_en.py +0 -0
  24. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_mlang/translator.py +0 -0
  25. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_web/__init__.py +0 -0
  26. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/easyrip_web/third_party_api.py +0 -0
  27. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/__init__.py +0 -0
  28. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/font_subset/__init__.py +0 -0
  29. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/font_subset/ass.py +0 -0
  30. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/font_subset/font.py +0 -0
  31. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/font_subset/subset.py +0 -0
  32. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/media_info.py +0 -0
  33. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/ripper/ripper.py +0 -0
  34. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip/utils.py +0 -0
  35. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip.egg-info/dependency_links.txt +0 -0
  36. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip.egg-info/entry_points.txt +0 -0
  37. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip.egg-info/requires.txt +0 -0
  38. {easyrip-4.1.0 → easyrip-4.3.0}/easyrip.egg-info/top_level.txt +0 -0
  39. {easyrip-4.1.0 → easyrip-4.3.0}/setup.cfg +0 -0
@@ -1,10 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easyrip
3
- Version: 4.1.0
4
- Project-URL: Repository, https://github.com/op200/EasyRip
3
+ Version: 4.3.0
4
+ Author: op200
5
+ License-Expression: AGPL-3.0-or-later
6
+ Project-URL: Homepage, https://github.com/op200/EasyRip
7
+ Project-URL: Source, https://github.com/op200/EasyRip
5
8
  Classifier: Topic :: Multimedia
6
9
  Classifier: Development Status :: 5 - Production/Stable
7
- Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
8
10
  Classifier: Programming Language :: Python :: 3.12
9
11
  Classifier: Programming Language :: Python :: 3.13
10
12
  Classifier: Programming Language :: Python :: 3.14
@@ -21,13 +23,7 @@ License-File: LICENSE
21
23
  Requires-Dist: prompt-toolkit>=3.0.52
22
24
  Requires-Dist: fonttools>=4.61.0
23
25
  Requires-Dist: pycryptodome>=3.21.0
24
- Dynamic: classifier
25
- Dynamic: description
26
- Dynamic: description-content-type
27
26
  Dynamic: license-file
28
- Dynamic: project-url
29
- Dynamic: requires-dist
30
- Dynamic: requires-python
31
27
 
32
28
  # Easy Rip
33
29
 
@@ -39,31 +35,17 @@ Easy Rip 网页版控制台](https://op200.github.io/EasyRip-WebPanel/)**
39
35
 
40
36
  ## Start
41
37
 
42
- * If you have Python environment
43
- 如果你有 Python 环境
38
+ 1. Install [Python](https://www.python.org/)
39
+ 安装 [Python](https://www.python.org/)
40
+ 2. Install Easy Rip using pip: `pip install -U easyrip`
41
+ 使用 pip 安装 Easy Rip: `pip install -U easyrip`
42
+ 3. The you can use Easy Rip directly, run the command `easyrip`
43
+ 然后你就可以直接 Easy Rip 了,运行命令 `easyrip`
44
44
 
45
- 1. You can `pip install -U git+https://github.com/op200/EasyRip.git` to pull the version from the repositoryand, or `pip install -U easyrip` to obtain the stable version.
46
- 你可以 `pip install -U git+https://github.com/op200/EasyRip.git` 获取仓库中的版本,或者 `pip install -U easyrip` 获取稳定版。
47
-
48
- 2. After installation, run `easyrip` on command.
49
- 安装后直接在命令行运行 `easyrip`。
50
-
51
- * Or if you want to download a standalone exe file (not recommended)
52
- 或者如果你想下载一个独立的可执行文件(不推荐)
53
-
54
- *
55
- Download exe in [Actions](https://github.com/op200/EasyRip/actions).
56
- Or download exe or bat script collection in [Releases](https://github.com/op200/EasyRip/releases).
57
-
58
- 在 [Actions](https://github.com/op200/EasyRip/actions) 中下载最新的 exe。
59
- 或者在 [Releases](https://github.com/op200/EasyRip/releases) 中下载 exe 或 bat 脚本包。
60
-
61
- *
62
- The file `BatchScriptPackage` in [Releases](https://github.com/op200/EasyRip/releases) is a bat script collection.
63
- It is used to facilitate ordinary users, it only has Chinese.
64
-
65
- [Releases](https://github.com/op200/EasyRip/releases) 中每隔一段时间发布一次名为 BatchScriptPackage 的 bat 脚本包
66
- 用于方便一般用户,其内只有中文
45
+ * (If you have special requirements and want to use a separate file, you can download it from [Github Actions](https://github.com/op200/EasyRip/actions))
46
+ (如果你有特殊需求,想使用独立文件,可以在 [Github Actions](https://github.com/op200/EasyRip/actions) 中下载)
47
+ * (The file `BatchScriptPackage` in [Releases](https://github.com/op200/EasyRip/releases) is a bat script collection. It is used to facilitate ordinary users, it only has Chinese.)
48
+ ([Releases](https://github.com/op200/EasyRip/releases) 中每隔一段时间发布一次名为 `BatchScriptPackage` bat 脚本包,用于方便一般用户,其内只有中文。)
67
49
 
68
50
  ## Usage
69
51
 
@@ -75,7 +57,7 @@ Run `easyrip`, input `help` to get help doc
75
57
 
76
58
  ## Dependency
77
59
 
78
- * ### Python 3.13 (must >=3.12)
60
+ * ### Python 3.14 (must >=3.12)
79
61
 
80
62
  If you want to develop, you need to install dependencies. If you just want to use them, you don't need to manually install dependencies.
81
63
  如果你想开发,需要安装依赖,如果你只是想使用,不需要手动安装依赖。
@@ -0,0 +1,65 @@
1
+ # Easy Rip
2
+
3
+ Self-use codec tool
4
+ 自用压制工具
5
+
6
+ **[Easy Rip Web Panel
7
+ Easy Rip 网页版控制台](https://op200.github.io/EasyRip-WebPanel/)**
8
+
9
+ ## Start
10
+
11
+ 1. Install [Python](https://www.python.org/)
12
+ 安装 [Python](https://www.python.org/)
13
+ 2. Install Easy Rip using pip: `pip install -U easyrip`
14
+ 使用 pip 安装 Easy Rip: `pip install -U easyrip`
15
+ 3. The you can use Easy Rip directly, run the command `easyrip`
16
+ 然后你就可以直接 Easy Rip 了,运行命令 `easyrip`
17
+
18
+ * (If you have special requirements and want to use a separate file, you can download it from [Github Actions](https://github.com/op200/EasyRip/actions))
19
+ (如果你有特殊需求,想使用独立文件,可以在 [Github Actions](https://github.com/op200/EasyRip/actions) 中下载)
20
+ * (The file `BatchScriptPackage` in [Releases](https://github.com/op200/EasyRip/releases) is a bat script collection. It is used to facilitate ordinary users, it only has Chinese.)
21
+ ([Releases](https://github.com/op200/EasyRip/releases) 中每隔一段时间发布一次名为 `BatchScriptPackage` 的 bat 脚本包,用于方便一般用户,其内只有中文。)
22
+
23
+ ## Usage
24
+
25
+ Run `easyrip`, input `help` to get help doc
26
+ 运行 `easyrip`,键入 `help` 获取帮助文档
27
+
28
+ [View usage in wiki
29
+ 在 Wiki 中查看用法](https://github.com/op200/EasyRip/wiki)
30
+
31
+ ## Dependency
32
+
33
+ * ### Python 3.14 (must >=3.12)
34
+
35
+ If you want to develop, you need to install dependencies. If you just want to use them, you don't need to manually install dependencies.
36
+ 如果你想开发,需要安装依赖,如果你只是想使用,不需要手动安装依赖。
37
+
38
+ ```pwsh
39
+ pip install -U prompt-toolkit fonttools pycryptodome
40
+ ```
41
+
42
+ * [prompt-toolkit](https://pypi.org/project/prompt-toolkit/)
43
+ * [fonttools](https://pypi.org/project/fonttools/)
44
+ * [pycryptodome](https://pypi.org/project/pycryptodome/)
45
+
46
+ * ### CLI
47
+
48
+ Command line dependencies are necessary.
49
+ 命令行依赖是必须的。
50
+
51
+ * [ffmpeg & ffprobe](https://ffmpeg.org/)
52
+ * [flac](https://xiph.org/flac/)
53
+ * [mp4box](https://gpac.io/)
54
+ * [mp4fpsmod](https://github.com/nu774/mp4fpsmod)
55
+ * [mkvpropedit & mkvmerge](https://mkvtoolnix.download/)
56
+ <!-- * [MediaInfo](https://mediaarea.net/en/MediaInfo) -->
57
+
58
+ ## Supported languages
59
+
60
+ * en
61
+ * zh-Hans-CN
62
+
63
+ If you want to add or modify translation, edit the `easyrip/easyrip_mlang`
64
+
65
+ Or add translate file, see [Wiki](https://github.com/op200/EasyRip/wiki/Language-file) for details
@@ -6,9 +6,10 @@ import Crypto
6
6
  import fontTools
7
7
  import prompt_toolkit
8
8
  from prompt_toolkit import ANSI, prompt
9
- from prompt_toolkit.completion import FuzzyCompleter, PathCompleter, merge_completers
9
+ from prompt_toolkit.completion import PathCompleter, merge_completers
10
10
  from prompt_toolkit.history import InMemoryHistory
11
- from prompt_toolkit.key_binding import KeyBindings
11
+ from prompt_toolkit.key_binding import KeyBindings, KeyPressEvent
12
+ from prompt_toolkit.keys import Keys
12
13
 
13
14
  from .easyrip_command import (
14
15
  Cmd_type,
@@ -18,7 +19,10 @@ from .easyrip_command import (
18
19
  OptCompleter,
19
20
  nested_dict,
20
21
  )
22
+ from .easyrip_config.config import Config_key, config
21
23
  from .easyrip_main import Ripper, get_input_prompt, init, log, run_command
24
+ from .easyrip_prompt import ConfigFileHistory, easyrip_prompt
25
+ from .global_val import C_D, C_Z
22
26
 
23
27
 
24
28
  def run() -> NoReturn:
@@ -36,11 +40,15 @@ def run() -> NoReturn:
36
40
 
37
41
  key_bindings = KeyBindings()
38
42
 
39
- @key_bindings.add("c-d")
40
- def _(event) -> None:
41
- event.app.current_buffer.insert_text("\x04") # ^D
43
+ @key_bindings.add(Keys.ControlC)
44
+ def _(event: KeyPressEvent) -> None:
45
+ event.app.exit(exception=KeyboardInterrupt, style="class:exiting")
42
46
 
43
- path_completer = FuzzyCompleter(PathCompleter())
47
+ @key_bindings.add(Keys.ControlD)
48
+ def _(event: KeyPressEvent) -> None:
49
+ event.app.current_buffer.insert_text(C_D)
50
+
51
+ path_completer = PathCompleter()
44
52
 
45
53
  def _ctv_to_nc(ctvs: Iterable[Cmd_type_val]) -> CmdCompleter:
46
54
  return CmdCompleter(
@@ -92,7 +100,11 @@ def run() -> NoReturn:
92
100
  }
93
101
 
94
102
  cmd_ctv_tuple = tuple(ct.value for ct in Cmd_type if ct != Cmd_type.Option)
95
- prompt_history = InMemoryHistory()
103
+ prompt_history = (
104
+ ConfigFileHistory(easyrip_prompt.PROMPT_HISTORY_FILE)
105
+ if config.get_user_profile(Config_key.prompt_history_save_file)
106
+ else InMemoryHistory()
107
+ )
96
108
  while True:
97
109
  try:
98
110
  command = prompt(
@@ -107,7 +119,7 @@ def run() -> NoReturn:
107
119
  history=prompt_history,
108
120
  complete_while_typing=True,
109
121
  )
110
- if command.startswith("\x1a"): # ^Z
122
+ if command.startswith(C_Z):
111
123
  raise EOFError
112
124
  except KeyboardInterrupt:
113
125
  continue
@@ -3,10 +3,11 @@ import itertools
3
3
  import textwrap
4
4
  from collections.abc import Iterable
5
5
  from dataclasses import dataclass
6
- from typing import Final, Self, TypeAlias, final
6
+ from typing import Final, Self, final
7
7
 
8
8
  from prompt_toolkit.completion import (
9
9
  Completer,
10
+ DeduplicateCompleter,
10
11
  FuzzyCompleter,
11
12
  FuzzyWordCompleter,
12
13
  NestedCompleter,
@@ -17,6 +18,7 @@ from prompt_toolkit.completion.base import CompleteEvent, Completion
17
18
  from prompt_toolkit.document import Document
18
19
 
19
20
  from . import global_val
21
+ from .easyrip_config.config_key import Config_key
20
22
 
21
23
 
22
24
  @final
@@ -175,19 +177,22 @@ class Cmd_type(enum.Enum):
175
177
  )
176
178
  run = Cmd_type_val(
177
179
  ("run",),
178
- param="[<run option>]",
180
+ param="[<run option>] [-multithreading <0 | 1>]",
179
181
  description=(
180
182
  "Run the Ripper in the Ripper list\n"
181
- " \n"
183
+ "\n"
182
184
  "Default:\n"
183
185
  " Only run\n"
184
- " \n"
186
+ "\n"
185
187
  "exit:\n"
186
188
  " Close program when run finished\n"
187
- " \n"
189
+ "\n"
188
190
  "shutdown [<sec>]:\n"
189
191
  " Shutdown when run finished\n"
190
- " Default: 60"
192
+ " Default: 60\n"
193
+ "\n"
194
+ "server [<address>]:[<port>]@[<password>]:\n"
195
+ " See the corresponding help for details"
191
196
  ),
192
197
  childs=(
193
198
  Cmd_type_val(("exit",)),
@@ -196,22 +201,18 @@ class Cmd_type(enum.Enum):
196
201
  )
197
202
  server = Cmd_type_val(
198
203
  ("server",),
199
- param="[[-a | -address] <address>[:<port>] [[-p | -password] <password>]]",
204
+ param="[<address>]:[<port>]@[<password>]",
200
205
  description=(
201
206
  "Boot web service\n"
202
207
  "Default: server localhost:0\n"
203
208
  "Client send command 'kill' can exit Ripper's run, note that FFmpeg needs to accept multiple ^C signals to forcibly terminate, and a single ^C signal will wait for the file output to be complete before terminating"
204
209
  ),
205
- childs=(
206
- Cmd_type_val(("-a", "-address")),
207
- Cmd_type_val(("-p", "-password")),
208
- ),
209
210
  )
210
211
  config = Cmd_type_val(
211
212
  ("config",),
212
213
  param="<config option>",
213
214
  description=(
214
- "regenerate | clear | clean | reset\n"
215
+ "regenerate | clear | clean\n"
215
216
  " Regenerate config file\n"
216
217
  "open\n"
217
218
  " Open the directory where the config file is located\n"
@@ -222,10 +223,27 @@ class Cmd_type(enum.Enum):
222
223
  " e.g. config set language zh"
223
224
  ),
224
225
  childs=(
225
- Cmd_type_val(("regenerate", "clear", "clean", "reset")),
226
+ Cmd_type_val(("regenerate", "clear", "clean")),
226
227
  Cmd_type_val(("open",)),
227
228
  Cmd_type_val(("list",)),
228
- Cmd_type_val(("set",)),
229
+ Cmd_type_val(
230
+ ("set",),
231
+ childs=tuple(Cmd_type_val((k,)) for k in Config_key._value2member_map_),
232
+ ),
233
+ ),
234
+ )
235
+ prompt = Cmd_type_val(
236
+ ("prompt",),
237
+ param="<prompt option>",
238
+ description=(
239
+ "history\n" # .
240
+ " Show prompt history\n"
241
+ "clear | clean\n"
242
+ " Delete history file"
243
+ ),
244
+ childs=(
245
+ Cmd_type_val(("history",)),
246
+ Cmd_type_val(("clear", "clean")),
229
247
  ),
230
248
  )
231
249
  translate = Cmd_type_val(
@@ -545,16 +563,19 @@ class Opt_type(enum.Enum):
545
563
  param="[<string>]",
546
564
  description=(
547
565
  "Run the Ripper from the Ripper list\n"
548
- " \n"
566
+ "\n"
549
567
  "Default:\n"
550
568
  " Only run\n"
551
- " \n"
569
+ "\n"
552
570
  "exit:\n"
553
571
  " Close program when run finished\n"
554
- " \n"
572
+ "\n"
555
573
  "shutdown [<sec>]:\n"
556
574
  " Shutdown when run finished\n"
557
575
  " Default: 60\n"
576
+ "\n"
577
+ "server [<address>]:[<port>]@[<password>]:\n"
578
+ " See the corresponding help for details"
558
579
  ),
559
580
  childs=(
560
581
  Cmd_type_val(("exit",)),
@@ -665,7 +686,7 @@ def get_help_doc() -> str:
665
686
  )
666
687
 
667
688
 
668
- nested_dict: TypeAlias = dict[str, "nested_dict | Completer"]
689
+ type nested_dict = dict[str, "nested_dict | Completer"]
669
690
  META_DICT_OPT_TYPE = {
670
691
  name: opt.value.param for opt in Opt_type for name in opt.value.names
671
692
  }
@@ -746,7 +767,17 @@ class OptCompleter(Completer):
746
767
  )
747
768
  )
748
769
 
749
- if isinstance(opt_tree_pos_list[-1], Completer):
770
+ if opt_tree_pos_list[-1] is not self.opt_tree and not text.endswith(" "):
771
+ yield from (
772
+ Completion(
773
+ text=words[-1],
774
+ start_position=-len(words[-1]),
775
+ display_meta=META_DICT_OPT_TYPE.get(words[-1], ""),
776
+ ),
777
+ Completion(text="", display="✔"),
778
+ )
779
+
780
+ elif isinstance(opt_tree_pos_list[-1], Completer):
750
781
  # 直接使用 PathCompleter 会因为上下文问题失效,所以将上文套进 NestedCompleter
751
782
  new_nd: nested_dict = {}
752
783
  new_nd_pos: nested_dict = new_nd
@@ -767,11 +798,22 @@ class OptCompleter(Completer):
767
798
 
768
799
  yield from merge_completers(
769
800
  (
770
- _nested_dict_to_nc(new_nd),
771
- FuzzyWordCompleter(
772
- words=tuple(opt_tree_pos_list[-1]),
773
- meta_dict=META_DICT_OPT_TYPE,
774
- WORD=True,
801
+ DeduplicateCompleter(
802
+ merge_completers(
803
+ (
804
+ _nested_dict_to_nc(new_nd),
805
+ FuzzyCompleter(_nested_dict_to_nc(new_nd), WORD=True),
806
+ )
807
+ )
808
+ ),
809
+ FuzzyCompleter(
810
+ WordCompleter(
811
+ words=tuple(opt_tree_pos_list[-1]),
812
+ meta_dict=META_DICT_OPT_TYPE,
813
+ WORD=True, # 匹配标点
814
+ match_middle=True,
815
+ ),
816
+ WORD=False,
775
817
  ),
776
818
  )
777
819
  ).get_completions(document=document, complete_event=complete_event)
@@ -779,10 +821,16 @@ class OptCompleter(Completer):
779
821
  else:
780
822
  yield from FuzzyCompleter(
781
823
  WordCompleter(
782
- words=tuple(opt_tree_pos_list[-1]),
824
+ words=tuple(
825
+ opt_tree_pos_list[-1] | {}
826
+ if text.endswith(" ")
827
+ or len(words) <= 1
828
+ or isinstance(opt_tree_pos_list[-2], Completer)
829
+ else opt_tree_pos_list[-2]
830
+ ),
783
831
  meta_dict=META_DICT_OPT_TYPE,
784
- WORD=True,
832
+ WORD=True, # 匹配标点
785
833
  match_middle=True,
786
834
  ),
787
- WORD=False,
835
+ WORD=not text.endswith(" "),
788
836
  ).get_completions(document=document, complete_event=complete_event)
@@ -1,26 +1,11 @@
1
- import enum
2
1
  import json
3
2
  import os
4
- import sys
5
3
  from pathlib import Path
6
4
 
7
- from . import global_val
8
- from .easyrip_log import log
9
- from .easyrip_mlang import all_supported_lang_map, gettext
10
-
11
- PROJECT_NAME = global_val.PROJECT_NAME
12
- CONFIG_VERSION = "2.9.4"
13
-
14
-
15
- class Config_key(enum.Enum):
16
- language = "language"
17
- check_update = "check_update"
18
- check_dependent = "check_dependent"
19
- startup_directory = "startup_directory"
20
- force_log_file_path = "force_log_file_path"
21
- log_print_level = "log_print_level"
22
- log_write_level = "log_write_level"
23
-
5
+ from ..easyrip_log import log
6
+ from ..easyrip_mlang import all_supported_lang_map, gettext
7
+ from ..global_val import CONFIG_DIR
8
+ from .config_key import CONFIG_VERSION, Config_key
24
9
 
25
10
  CONFIG_DEFAULT_DICT: dict[Config_key, str | bool] = {
26
11
  Config_key.language: "auto",
@@ -30,6 +15,7 @@ CONFIG_DEFAULT_DICT: dict[Config_key, str | bool] = {
30
15
  Config_key.force_log_file_path: "",
31
16
  Config_key.log_print_level: log.LogLevel.send.name,
32
17
  Config_key.log_write_level: log.LogLevel.send.name,
18
+ Config_key.prompt_history_save_file: True,
33
19
  }
34
20
 
35
21
 
@@ -40,19 +26,8 @@ class config:
40
26
 
41
27
  @classmethod
42
28
  def init(cls) -> None:
43
- if sys.platform == "win32":
44
- # Windows: C:\Users\<用户名>\AppData\Roaming\<app_name>
45
- cls._config_dir = Path(os.getenv("APPDATA", ""))
46
- elif sys.platform == "darwin":
47
- # macOS: ~/Library/Application Support/<app_name>
48
- cls._config_dir = (
49
- Path(os.path.expanduser("~")) / "Library" / "Application Support"
50
- )
51
- else:
52
- # Linux: ~/.config/<app_name>
53
- cls._config_dir = Path(os.path.expanduser("~")) / ".config"
54
- cls._config_dir = Path(cls._config_dir) / PROJECT_NAME
55
- cls._config_file = Path(cls._config_dir) / "config.json"
29
+ cls._config_dir = CONFIG_DIR
30
+ cls._config_file = cls._config_dir / "config.json"
56
31
 
57
32
  if not cls._config_file.is_file():
58
33
  cls._config_dir.mkdir(exist_ok=True)
@@ -149,7 +124,11 @@ class config:
149
124
  return cls._write_config()
150
125
 
151
126
  @classmethod
152
- def get_user_profile(cls, key: str) -> str | int | float | bool | None:
127
+ 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
131
+
153
132
  if cls._config is None:
154
133
  cls._read_config()
155
134
  if cls._config is None:
@@ -216,6 +195,10 @@ class config:
216
195
  CONFIG_DEFAULT_DICT[Config_key.log_write_level],
217
196
  ", ".join(log.LogLevel._member_names_),
218
197
  ),
198
+ Config_key.prompt_history_save_file.value: gettext(
199
+ "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],
201
+ ),
219
202
  }
220
203
  | (cls._config or {})
221
204
  ).get(key, "None about")
@@ -0,0 +1,14 @@
1
+ import enum
2
+
3
+ CONFIG_VERSION = "4.2.0"
4
+
5
+
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"