easyrip 4.5.0__py3-none-any.whl → 4.6.0__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/__main__.py +6 -3
- easyrip/easyrip_command.py +2 -2
- easyrip/easyrip_config/config.py +87 -22
- easyrip/easyrip_config/config_key.py +23 -9
- easyrip/easyrip_main.py +31 -41
- easyrip/easyrip_mlang/lang_zh_Hans_CN.py +9 -21
- easyrip/global_val.py +1 -1
- easyrip/utils.py +80 -1
- {easyrip-4.5.0.dist-info → easyrip-4.6.0.dist-info}/METADATA +1 -1
- {easyrip-4.5.0.dist-info → easyrip-4.6.0.dist-info}/RECORD +14 -14
- {easyrip-4.5.0.dist-info → easyrip-4.6.0.dist-info}/WHEEL +0 -0
- {easyrip-4.5.0.dist-info → easyrip-4.6.0.dist-info}/entry_points.txt +0 -0
- {easyrip-4.5.0.dist-info → easyrip-4.6.0.dist-info}/licenses/LICENSE +0 -0
- {easyrip-4.5.0.dist-info → easyrip-4.6.0.dist-info}/top_level.txt +0 -0
easyrip/__main__.py
CHANGED
|
@@ -103,7 +103,7 @@ def run() -> NoReturn:
|
|
|
103
103
|
cmd_ctv_tuple = tuple(ct.value for ct in Cmd_type if ct != Cmd_type.Option)
|
|
104
104
|
prompt_history = (
|
|
105
105
|
ConfigFileHistory(easyrip_prompt.PROMPT_HISTORY_FILE)
|
|
106
|
-
if config.get_user_profile(Config_key.
|
|
106
|
+
if config.get_user_profile(Config_key.save_prompt_history)
|
|
107
107
|
else InMemoryHistory()
|
|
108
108
|
)
|
|
109
109
|
|
|
@@ -129,8 +129,11 @@ def run() -> NoReturn:
|
|
|
129
129
|
log.debug("Manually force exit")
|
|
130
130
|
sys.exit(0)
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
try:
|
|
133
|
+
if not run_command(command):
|
|
134
|
+
log.warning("Stop run command")
|
|
135
|
+
except KeyboardInterrupt:
|
|
136
|
+
log.warning("Manually stop run command")
|
|
134
137
|
|
|
135
138
|
|
|
136
139
|
if __name__ == "__main__":
|
easyrip/easyrip_command.py
CHANGED
|
@@ -244,7 +244,7 @@ class Cmd_type(enum.Enum):
|
|
|
244
244
|
Cmd_type_val(("list",)),
|
|
245
245
|
Cmd_type_val(
|
|
246
246
|
("set",),
|
|
247
|
-
childs=tuple(Cmd_type_val((k,)) for k in Config_key.
|
|
247
|
+
childs=tuple(Cmd_type_val((k,)) for k in Config_key._member_map_),
|
|
248
248
|
),
|
|
249
249
|
),
|
|
250
250
|
)
|
|
@@ -490,7 +490,7 @@ class Opt_type(enum.Enum):
|
|
|
490
490
|
"Audio encoder:\n" # .
|
|
491
491
|
f"{Audio_codec.to_help_string(' ')}"
|
|
492
492
|
),
|
|
493
|
-
childs=(Cmd_type_val((
|
|
493
|
+
childs=(Cmd_type_val(tuple(Audio_codec._value2member_map_)),),
|
|
494
494
|
)
|
|
495
495
|
_b_a = Cmd_type_val(
|
|
496
496
|
("-b:a",),
|
easyrip/easyrip_config/config.py
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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.
|
|
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(
|
|
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,
|
|
129
|
-
|
|
130
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
3
|
+
CONFIG_VERSION = "4.6.0"
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class Config_key(enum.Enum):
|
|
7
|
-
language =
|
|
8
|
-
check_update =
|
|
9
|
-
check_dependent =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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_main.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import ast
|
|
1
2
|
import ctypes
|
|
2
3
|
import itertools
|
|
3
4
|
import json
|
|
@@ -58,16 +59,15 @@ def log_new_ver(
|
|
|
58
59
|
log.info(
|
|
59
60
|
"\n"
|
|
60
61
|
+ gettext(
|
|
61
|
-
"{} has new version {}.
|
|
62
|
+
"{} has new version ({} -> {}). Suggest upgrading it: {}",
|
|
62
63
|
program_name,
|
|
64
|
+
old_ver,
|
|
63
65
|
new_ver,
|
|
64
66
|
dl_url,
|
|
65
67
|
)
|
|
66
68
|
)
|
|
67
|
-
# print(get_input_prompt(True), end="")
|
|
68
69
|
except Exception as e:
|
|
69
70
|
log.warning(f"\n{e}", is_format=False, deep=True)
|
|
70
|
-
# print(get_input_prompt(True), end="")
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
def check_env() -> None:
|
|
@@ -185,20 +185,6 @@ def check_env() -> None:
|
|
|
185
185
|
_url,
|
|
186
186
|
)
|
|
187
187
|
|
|
188
|
-
# _name, _url = "MediaInfo", "https://mediaarea.net/en/MediaInfo/Download"
|
|
189
|
-
# if not shutil.which(_name):
|
|
190
|
-
# log.warning(
|
|
191
|
-
# "\n"
|
|
192
|
-
# + gettext(
|
|
193
|
-
# "{} not found, download it: {}", _name, f"(CLI ver) {_url}"
|
|
194
|
-
# )
|
|
195
|
-
# )
|
|
196
|
-
# log.print(get_input_prompt(), end="")
|
|
197
|
-
# elif not subprocess.run(
|
|
198
|
-
# "mediainfo --version", capture_output=True, text=True
|
|
199
|
-
# ).stdout:
|
|
200
|
-
# log.error("The MediaInfo must be CLI ver")
|
|
201
|
-
|
|
202
188
|
if config.get_user_profile(Config_key.check_update):
|
|
203
189
|
log_new_ver(
|
|
204
190
|
easyrip_web.github.get_latest_release_ver(
|
|
@@ -208,18 +194,20 @@ def check_env() -> None:
|
|
|
208
194
|
PROJECT_NAME,
|
|
209
195
|
f"{global_val.PROJECT_URL}\n{
|
|
210
196
|
gettext(
|
|
211
|
-
'
|
|
212
|
-
f'{sys.executable
|
|
197
|
+
'Suggest running the following command to upgrade using pip: {}',
|
|
198
|
+
f'{f'"{sys.executable}" -m ' if sys.executable.lower().endswith("python.exe") else ""}pip install -U easyrip',
|
|
213
199
|
)
|
|
214
200
|
}",
|
|
215
201
|
)
|
|
216
202
|
|
|
217
|
-
# sys.stdout.flush()
|
|
218
|
-
# sys.stderr.flush()
|
|
219
203
|
change_title(PROJECT_TITLE)
|
|
220
204
|
|
|
221
205
|
except Exception as e:
|
|
222
|
-
log.error(
|
|
206
|
+
log.error(
|
|
207
|
+
f"The function {check_env.__name__} error: {e!r} {e}",
|
|
208
|
+
is_format=False,
|
|
209
|
+
deep=True,
|
|
210
|
+
)
|
|
223
211
|
|
|
224
212
|
|
|
225
213
|
def get_input_prompt(is_color: bool = False) -> str:
|
|
@@ -674,6 +662,7 @@ def run_command(command: Iterable[str] | str) -> bool:
|
|
|
674
662
|
easyrip_web.run_server(*_params)
|
|
675
663
|
|
|
676
664
|
case Cmd_type.config:
|
|
665
|
+
log.debug(cmd_list)
|
|
677
666
|
match cmd_list[1]:
|
|
678
667
|
case "list" | "":
|
|
679
668
|
config.show_config_list()
|
|
@@ -685,25 +674,16 @@ def run_command(command: Iterable[str] | str) -> bool:
|
|
|
685
674
|
case "set":
|
|
686
675
|
_key = cmd_list[2]
|
|
687
676
|
_val = cmd_list[3]
|
|
688
|
-
|
|
677
|
+
|
|
678
|
+
if (_old_val := config.get_user_profile(_key)) is None:
|
|
679
|
+
return False
|
|
689
680
|
|
|
690
681
|
try:
|
|
691
|
-
_val =
|
|
692
|
-
except ValueError:
|
|
693
|
-
|
|
694
|
-
case "true" | "True":
|
|
695
|
-
_val = True
|
|
696
|
-
case "false" | "False":
|
|
697
|
-
_val = False
|
|
698
|
-
else:
|
|
699
|
-
if (_val_int := int(_val)) == _val:
|
|
700
|
-
_val = _val_int
|
|
682
|
+
_val = ast.literal_eval(_val)
|
|
683
|
+
except (ValueError, SyntaxError):
|
|
684
|
+
pass
|
|
701
685
|
|
|
702
|
-
if
|
|
703
|
-
(_old_val is _val)
|
|
704
|
-
if isinstance(_val, bool) or isinstance(_old_val, bool)
|
|
705
|
-
else (_old_val == _val)
|
|
706
|
-
):
|
|
686
|
+
if _old_val == _val:
|
|
707
687
|
log.info(
|
|
708
688
|
"The new value is the same as the old value, cancel the modification",
|
|
709
689
|
)
|
|
@@ -1102,7 +1082,7 @@ def init(is_first_run: bool = False) -> None:
|
|
|
1102
1082
|
|
|
1103
1083
|
# 设置日志文件路径名
|
|
1104
1084
|
log.html_filename = gettext("encoding_log.html")
|
|
1105
|
-
if _path := str(config.get_user_profile(
|
|
1085
|
+
if _path := str(config.get_user_profile(Config_key.force_log_file_path) or ""):
|
|
1106
1086
|
log.html_filename = os.path.join(_path, log.html_filename)
|
|
1107
1087
|
|
|
1108
1088
|
# 设置日志级别
|
|
@@ -1119,8 +1099,18 @@ def init(is_first_run: bool = False) -> None:
|
|
|
1119
1099
|
if is_first_run:
|
|
1120
1100
|
# 设置启动目录
|
|
1121
1101
|
try:
|
|
1122
|
-
if
|
|
1123
|
-
|
|
1102
|
+
if _startup_dir := config.get_user_profile(Config_key.startup_dir):
|
|
1103
|
+
if _startup_dir_blacklist := config.get_user_profile(
|
|
1104
|
+
Config_key.startup_dir_blacklist
|
|
1105
|
+
):
|
|
1106
|
+
if any(
|
|
1107
|
+
Path.cwd().samefile(d)
|
|
1108
|
+
for d in map(Path, _startup_dir_blacklist)
|
|
1109
|
+
if d.is_dir()
|
|
1110
|
+
):
|
|
1111
|
+
os.chdir(_startup_dir)
|
|
1112
|
+
else:
|
|
1113
|
+
os.chdir(_startup_dir)
|
|
1124
1114
|
except Exception as e:
|
|
1125
1115
|
log.error(f"{e!r} {e}", deep=True)
|
|
1126
1116
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from ..easyrip_command import Cmd_type, Opt_type
|
|
1
|
+
from ..easyrip_command import Audio_codec, Cmd_type, Opt_type, Preset_name
|
|
2
2
|
from .global_lang_val import (
|
|
3
3
|
Lang_tag,
|
|
4
4
|
Lang_tag_language,
|
|
@@ -135,18 +135,8 @@ LANG_MAP: dict[str, str] = {
|
|
|
135
135
|
),
|
|
136
136
|
Opt_type._preset.value.description: (
|
|
137
137
|
"设置预设\n"
|
|
138
|
-
"预设名:\n"
|
|
139
|
-
"
|
|
140
|
-
" subset\n"
|
|
141
|
-
" copy\n"
|
|
142
|
-
" flac\n"
|
|
143
|
-
" x264fast x264slow\n"
|
|
144
|
-
" x265fast4 x265fast3 x265fast2 x265fast x265slow x265full\n"
|
|
145
|
-
" svtav1\n"
|
|
146
|
-
" vvenc\n"
|
|
147
|
-
" h264_amf h264_nvenc h264_qsv\n"
|
|
148
|
-
" hevc_amf hevc_nvenc hevc_qsv\n"
|
|
149
|
-
" av1_amf av1_nvenc av1_qsv"
|
|
138
|
+
"预设名:\n" # .
|
|
139
|
+
f"{Preset_name.to_help_string(' ')}"
|
|
150
140
|
),
|
|
151
141
|
Opt_type._pipe.value.description: (
|
|
152
142
|
"选择一个 vpy 文件作为管道的输入, 这个 vpy 必须有 input 全局变量\n"
|
|
@@ -209,11 +199,8 @@ LANG_MAP: dict[str, str] = {
|
|
|
209
199
|
),
|
|
210
200
|
Opt_type._c_a.value.description: (
|
|
211
201
|
"设置音频编码器\n"
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
" copy\n"
|
|
215
|
-
" libopus\n"
|
|
216
|
-
" flac"
|
|
202
|
+
"音频编码器:\n" # .
|
|
203
|
+
f"{Audio_codec.to_help_string(' ')}"
|
|
217
204
|
),
|
|
218
205
|
Opt_type._b_a.value.description: "设置音频码率。默认值 '160k'",
|
|
219
206
|
Opt_type._muxer.value.description: (
|
|
@@ -286,7 +273,7 @@ LANG_MAP: dict[str, str] = {
|
|
|
286
273
|
"例如 -p subset 或 -p copy"
|
|
287
274
|
),
|
|
288
275
|
# utils
|
|
289
|
-
"{} has new version {}.
|
|
276
|
+
"{} has new version ({} -> {}). Suggest upgrading it: {}": "检测到 {} 有新版本 ({} -> {})。建议更新: {}",
|
|
290
277
|
"{} not found, download it: {}": "没找到 {}, 在此下载: {}",
|
|
291
278
|
"flac ver ({}) must >= 1.5.0": "flac 版本 ({}) 必须 >= 1.5.0",
|
|
292
279
|
# main
|
|
@@ -316,7 +303,7 @@ LANG_MAP: dict[str, str] = {
|
|
|
316
303
|
"There is no audio stream in the video, so '-c:a' cannot be used": "视频中没有音频流,所以无法使用 '-c:a'",
|
|
317
304
|
"Unsupported '{}' param: {}": "'{}' 不支持此参数: {}",
|
|
318
305
|
"Manually force exit": "手动强制退出",
|
|
319
|
-
"
|
|
306
|
+
"Suggest running the following command to upgrade using pip: {}": "建议运行以下命令以使用 pip 更新: {}",
|
|
320
307
|
"Wrong sec in -shutdown, change to default 60s": "-shutdown 设定的秒数错误, 改为默认值 60s",
|
|
321
308
|
"Current work directory has an other Easy Rip is running: {}": "当前工作目录存在其他 Easy Rip 正在运行: {}",
|
|
322
309
|
"Stop run command": "命令执行终止",
|
|
@@ -359,7 +346,8 @@ LANG_MAP: dict[str, str] = {
|
|
|
359
346
|
"Config data is not found": "配置文件数据不存在",
|
|
360
347
|
"User profile is not found, regenerate config": "用户配置文件不存在, 重新生成配置",
|
|
361
348
|
"User profile is not a valid dictionary": "用户配置文件不是有效的字典",
|
|
362
|
-
"User profile is not found": "
|
|
349
|
+
"User profile is not found in config file": "用户配置文件不存在于配置文件",
|
|
350
|
+
"Type mismatch: need '{}'": "类型不匹配: 需要 '{}'",
|
|
363
351
|
"Key '{}' is not found in user profile": "用户配置文件中不存在 {}",
|
|
364
352
|
"Save prompt history to config directory, otherwise save to memory. Take effect after reboot. Default: {}": "将 prompt 历史保存到 config 目录,否则保存到内存。重启后生效。默认: {}",
|
|
365
353
|
# config about
|
easyrip/global_val.py
CHANGED
|
@@ -3,7 +3,7 @@ import sys
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
PROJECT_NAME = "Easy Rip"
|
|
6
|
-
PROJECT_VERSION = "4.
|
|
6
|
+
PROJECT_VERSION = "4.6.0"
|
|
7
7
|
PROJECT_TITLE = f"{PROJECT_NAME} v{PROJECT_VERSION}"
|
|
8
8
|
PROJECT_URL = "https://github.com/op200/EasyRip"
|
|
9
9
|
PROJECT_RELEASE_API = "https://api.github.com/repos/op200/EasyRip/releases/latest"
|
easyrip/utils.py
CHANGED
|
@@ -7,7 +7,7 @@ import sys
|
|
|
7
7
|
import time
|
|
8
8
|
from itertools import zip_longest
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Final
|
|
10
|
+
from typing import Final, get_args, get_origin
|
|
11
11
|
|
|
12
12
|
from Crypto.Cipher import AES as CryptoAES
|
|
13
13
|
from Crypto.Util.Padding import pad, unpad
|
|
@@ -207,3 +207,82 @@ def time_str_to_sec(s: str) -> float:
|
|
|
207
207
|
def non_ascii_str_len(s: str) -> int:
|
|
208
208
|
"""非 ASCII 字符算作 2 宽度"""
|
|
209
209
|
return sum(2 - int(ord(c) < 256) for c in s)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def type_match(val, b: type) -> bool:
|
|
213
|
+
"""
|
|
214
|
+
检查值是否匹配给定的类型(支持泛型)
|
|
215
|
+
|
|
216
|
+
支持的类型包括:
|
|
217
|
+
- 基本类型: int, str, list, dict, tuple, set
|
|
218
|
+
- 泛型类型: list[str], dict[str, int], tuple[int, ...]
|
|
219
|
+
- 联合类型: int | str, Union[int, str]
|
|
220
|
+
- 可选类型: Optional[str]
|
|
221
|
+
- 嵌套泛型: list[list[str]], dict[str, list[int]]
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
val: 要检查的值
|
|
225
|
+
b: 目标类型,可以是普通类型或泛型
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
bool: 值是否匹配目标类型
|
|
229
|
+
|
|
230
|
+
"""
|
|
231
|
+
b_org = get_origin(b)
|
|
232
|
+
|
|
233
|
+
# 如果不是泛型类型,直接使用 isinstance
|
|
234
|
+
if b_org is None:
|
|
235
|
+
return isinstance(val, b)
|
|
236
|
+
|
|
237
|
+
# 首先检查是否是 b_org 的实例
|
|
238
|
+
if not isinstance(val, b_org):
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
# 获取类型参数
|
|
242
|
+
args = get_args(b)
|
|
243
|
+
if not args: # 没有类型参数,如 List
|
|
244
|
+
return True
|
|
245
|
+
|
|
246
|
+
# 根据不同的原始类型进行检查
|
|
247
|
+
if b_org is list:
|
|
248
|
+
# list[T] 检查
|
|
249
|
+
if len(args) == 1:
|
|
250
|
+
elem_type = args[0]
|
|
251
|
+
return all(type_match(item, elem_type) for item in val)
|
|
252
|
+
|
|
253
|
+
elif b_org is tuple:
|
|
254
|
+
# tuple[T1, T2, ...] 或 tuple[T, ...] 检查
|
|
255
|
+
if len(args) == 2 and args[1] is ...: # 可变长度元组
|
|
256
|
+
elem_type = args[0]
|
|
257
|
+
return all(type_match(item, elem_type) for item in val)
|
|
258
|
+
# 固定长度元组
|
|
259
|
+
if len(val) != len(args):
|
|
260
|
+
return False
|
|
261
|
+
return all(type_match(item, t) for item, t in zip(val, args, strict=False))
|
|
262
|
+
|
|
263
|
+
elif b_org is dict:
|
|
264
|
+
# dict[K, V] 检查
|
|
265
|
+
if len(args) == 2:
|
|
266
|
+
key_type, value_type = args
|
|
267
|
+
return all(
|
|
268
|
+
type_match(k, key_type) and type_match(v, value_type)
|
|
269
|
+
for k, v in val.items()
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
elif b_org is set:
|
|
273
|
+
# set[T] 检查
|
|
274
|
+
if len(args) == 1:
|
|
275
|
+
elem_type = args[0]
|
|
276
|
+
return all(type_match(item, elem_type) for item in val)
|
|
277
|
+
|
|
278
|
+
elif b_org is frozenset:
|
|
279
|
+
# frozenset[T] 检查
|
|
280
|
+
if len(args) == 1:
|
|
281
|
+
elem_type = args[0]
|
|
282
|
+
return all(type_match(item, elem_type) for item in val)
|
|
283
|
+
|
|
284
|
+
elif hasattr(b_org, "__name__") and b_org.__name__ == "Union":
|
|
285
|
+
# Union[T1, T2, ...] 或 T1 | T2 检查
|
|
286
|
+
return any(type_match(val, t) for t in args)
|
|
287
|
+
|
|
288
|
+
return True
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
easyrip/__init__.py,sha256=PIvSPDgswsIkWL4dsCe87knnxKmtvcrWYzmqAwZix_M,765
|
|
2
|
-
easyrip/__main__.py,sha256=
|
|
3
|
-
easyrip/easyrip_command.py,sha256=
|
|
2
|
+
easyrip/__main__.py,sha256=5t5NjuTSFW6jDp_HH4rTX8EOlf-GJI5HuTSwwndkw_I,4557
|
|
3
|
+
easyrip/easyrip_command.py,sha256=vuT9xg2OCuUXHH58BxcFGbzrzLUzlpynjGzjtDsBnCk,27837
|
|
4
4
|
easyrip/easyrip_log.py,sha256=0V5wBwbqWt56w_NHoLmQmkTHPnPLkYZCAbhDSYnLnDw,15611
|
|
5
|
-
easyrip/easyrip_main.py,sha256=
|
|
5
|
+
easyrip/easyrip_main.py,sha256=qF_u552kkVj8nnKNd46jHfkNwTODQfR297rISRgJkpU,43311
|
|
6
6
|
easyrip/easyrip_prompt.py,sha256=A5S7ybeJSGFkCmwdJ9TCQ_-lde7NWgkbFytZ2KnvkWI,2145
|
|
7
|
-
easyrip/global_val.py,sha256=
|
|
8
|
-
easyrip/utils.py,sha256=
|
|
9
|
-
easyrip/easyrip_config/config.py,sha256=
|
|
10
|
-
easyrip/easyrip_config/config_key.py,sha256=
|
|
7
|
+
easyrip/global_val.py,sha256=dBVsU5OVbawpZ64k7QOrad1gQRa8yVV6Z0wKzAFKMMY,773
|
|
8
|
+
easyrip/utils.py,sha256=A2IuZ8-yxhpjNTIDXH1SqU7qOWXtMhU7llHwebEu8LQ,8715
|
|
9
|
+
easyrip/easyrip_config/config.py,sha256=aj6Vg1rJkvICSTZ0ZONznR_MkvVr5u5ngkX_zfZopvU,9859
|
|
10
|
+
easyrip/easyrip_config/config_key.py,sha256=_jjdKOunskUoG7UUWOz3QZK-s4LF_x6hmM9MKttyS2Q,766
|
|
11
11
|
easyrip/easyrip_mlang/__init__.py,sha256=QHZt4BYJFkJuaPkN89pt_zkM2grifJakyRZbeyfH8f4,1893
|
|
12
12
|
easyrip/easyrip_mlang/global_lang_val.py,sha256=Un20KGMVVMQbOaV_7VaHg3E1dvK2Y7kI1cPzq_sFWKY,9984
|
|
13
13
|
easyrip/easyrip_mlang/lang_en.py,sha256=heUSPeVtY1Nf9eDhrjPM28N3PLsu62op3llbXAfXvAs,140
|
|
14
|
-
easyrip/easyrip_mlang/lang_zh_Hans_CN.py,sha256=
|
|
14
|
+
easyrip/easyrip_mlang/lang_zh_Hans_CN.py,sha256=UhDwCofxh7ku5weVzcLV2Xel9_EzgjR8_Rbw9FJ9j0U,18530
|
|
15
15
|
easyrip/easyrip_mlang/translator.py,sha256=Vg0S0p2rpMNAy3LHTdK7qKFdkPEXlOoCCXcaH7PyAC4,5939
|
|
16
16
|
easyrip/easyrip_web/__init__.py,sha256=tMyEeaSGeEJjND7MF0MBv9aDiDgaO3MOnppwxA70U2c,177
|
|
17
17
|
easyrip/easyrip_web/http_server.py,sha256=iyulCAFQrJlz86Lrr-Dm3fhOnNCf79Bp6fVHhr0ephY,8350
|
|
@@ -23,9 +23,9 @@ easyrip/ripper/sub_and_font/__init__.py,sha256=cBT7mxL7RRFaJXFPXuZ7RT-YK6FbnanaU
|
|
|
23
23
|
easyrip/ripper/sub_and_font/ass.py,sha256=eGi1eIDWAV1Ti_BYIAcAMwrAlXJ5f_zGYte3nNu4PeE,25532
|
|
24
24
|
easyrip/ripper/sub_and_font/font.py,sha256=pzRtMrcL3ATFOMM5nsJQqSBbZtrnRodIgxLkjHai7kg,8075
|
|
25
25
|
easyrip/ripper/sub_and_font/subset.py,sha256=VsFYTFuVWXW9ltkqWZIiwOIh-nGDKmW1tUv3oi5kpWw,17815
|
|
26
|
-
easyrip-4.
|
|
27
|
-
easyrip-4.
|
|
28
|
-
easyrip-4.
|
|
29
|
-
easyrip-4.
|
|
30
|
-
easyrip-4.
|
|
31
|
-
easyrip-4.
|
|
26
|
+
easyrip-4.6.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
27
|
+
easyrip-4.6.0.dist-info/METADATA,sha256=IlgOWhd9fLGMssLGVZzDfZGtsfcHZyA10LhnHAtcxB4,3506
|
|
28
|
+
easyrip-4.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
29
|
+
easyrip-4.6.0.dist-info/entry_points.txt,sha256=D6GBMMTzZ-apgX76KyZ6jxMmIFqGYwU9neeLLni_qKI,49
|
|
30
|
+
easyrip-4.6.0.dist-info/top_level.txt,sha256=kuEteBXm-Gf90jRQgH3-fTo-Z-Q6czSuUEqY158H4Ww,8
|
|
31
|
+
easyrip-4.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|