This commit is contained in:
张宏博 2025-12-19 16:20:53 +08:00
commit 450edbc9bb
103 changed files with 96831 additions and 0 deletions

BIN
DecorateCost.xlsx Normal file

Binary file not shown.

BIN
DecorateCost_sorted.xlsx Normal file

Binary file not shown.

39
Excel查找工具.spec Normal file
View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['find_in_xlsx_gui.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='Excel查找工具',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='NONE',
)

View File

@ -0,0 +1,9 @@
{
"paths": {
"MeowmentDebugtool": "E:/WorkSpace/MeowMentDebugTool/Publish"
},
"servers": {
"局域网服务器": "192.168.1.120",
"老服务器byway": "https://npm.bywaystudios.com/"
}
}

View File

@ -0,0 +1,4 @@
{
"last_selected_server": "局域网服务器",
"last_selected_path": "MeowmentDebugtool"
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,239 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional), webbrowser (delayed), psutil (optional), netrc (delayed, conditional), getpass (delayed)
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
missing module named fcntl - imported by subprocess (optional)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
missing module named org - imported by pickle (optional)
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional)
missing module named resource - imported by posix (top-level)
missing module named 'org.python' - imported by copy (optional), xml.sax (delayed, conditional)
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
missing module named _scproxy - imported by urllib.request (conditional)
missing module named termios - imported by tty (top-level), getpass (optional)
missing module named 'java.lang' - imported by platform (delayed, optional), xml.sax._exceptions (conditional)
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
missing module named pyimod02_importers - imported by E:\SelfSpace\pythontool\.venv\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
missing module named olefile - imported by PIL.FpxImagePlugin (top-level), PIL.MicImagePlugin (top-level)
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
missing module named annotationlib - imported by typing_extensions (conditional)
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
missing module named charset_normalizer - imported by numpy.f2py.crackfortran (optional)
missing module named vms_lib - imported by platform (delayed, optional)
missing module named java - imported by platform (delayed)
missing module named _winreg - imported by platform (delayed, optional)
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, optional)
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
missing module named threadpoolctl - imported by numpy.lib._utils_impl (delayed, optional)
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.vecmat - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.vecdot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.ushort - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.unsignedinteger - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.ulonglong - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.ulong - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.uintp - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.uintc - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.uint64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.uint32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.uint16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.uint - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.ubyte - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.trunc - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.true_divide - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._function_base_impl (top-level), numpy (conditional)
missing module named numpy._core.trace - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.timedelta64 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.tensordot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.tanh - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.tan - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.swapaxes - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.sum - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.subtract - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.str_ - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.square - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.sqrt - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
missing module named numpy._core.spacing - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.sort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.sinh - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.result_type - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional), numpy.fft._pocketfft (top-level)
missing module named numpy._core.remainder - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.reciprocal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
missing module named numpy._core.radians - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.rad2deg - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.prod - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.power - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.positive - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.pi - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.outer - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.ones - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.object_ - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.number - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.not_equal - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.newaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.negative - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.ndarray - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy.lib._utils_impl (top-level), numpy (conditional)
missing module named numpy._core.multiply - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.moveaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.modf - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.mod - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.minimum - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.maximum - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.max - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.matvec - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.matrix_transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.matmul - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.longlong - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.longdouble - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.long - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.logical_xor - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.logical_or - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.logical_not - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.logical_and - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.logaddexp2 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.logaddexp - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.log2 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.log1p - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.log - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.linspace - imported by numpy._core (top-level), numpy.lib._index_tricks_impl (top-level), numpy (conditional)
missing module named numpy._core.less_equal - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.less - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.left_shift - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.ldexp - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.lcm - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.isscalar - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.isnat - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
missing module named numpy._core.isnan - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.isfinite - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.intp - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.integer - imported by numpy._core (conditional), numpy (conditional), numpy.fft._helper (top-level)
missing module named numpy._core.intc - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.int64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.int32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.int16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.int8 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.inf - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.inexact - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.iinfo - imported by numpy._core (top-level), numpy.lib._twodim_base_impl (top-level), numpy (conditional)
missing module named numpy._core.hypot - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.hstack - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.heaviside - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.half - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.greater_equal - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.greater - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.gcd - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.frompyfunc - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.frexp - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.fmod - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.fmin - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.fmax - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.floor_divide - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.floor - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.floating - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.float_power - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.float32 - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.float16 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.finfo - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.fabs - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.expm1 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.exp - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.euler_gamma - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.errstate - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.equal - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.empty_like - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
missing module named numpy._core.empty - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
missing module named numpy._core.e - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.double - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.dot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.divmod - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.divide - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.diagonal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.degrees - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.deg2rad - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.datetime64 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.csingle - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.cross - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.count_nonzero - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.cosh - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.cos - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.copysign - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.conjugate - imported by numpy._core (conditional), numpy (conditional), numpy.fft._pocketfft (top-level)
missing module named numpy._core.conj - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.complexfloating - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.complex64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
missing module named numpy._core.clongdouble - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.character - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.ceil - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.cdouble - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.cbrt - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.bytes_ - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.byte - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.bool_ - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.bitwise_xor - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.bitwise_or - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.bitwise_count - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.bitwise_and - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.atleast_3d - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
missing module named numpy._core.atleast_2d - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.atleast_1d - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.asarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._array_utils_impl (top-level), numpy (conditional), numpy.fft._helper (top-level), numpy.fft._pocketfft (top-level)
missing module named numpy._core.asanyarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.array_repr - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
missing module named numpy._core.array2string - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.array - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
missing module named numpy._core.argsort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.arctanh - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arctan2 - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arctan - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arcsinh - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arcsin - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arccosh - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arccos - imported by numpy._core (conditional), numpy (conditional)
missing module named numpy._core.arange - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
missing module named numpy._core.amin - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.amax - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named numpy._core.all - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
missing module named yaml - imported by numpy.__config__ (delayed)
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
missing module named defusedxml - imported by openpyxl.xml (delayed, optional), PIL.Image (optional)
missing module named 'defusedxml.ElementTree' - imported by openpyxl.xml.functions (conditional)
missing module named 'lxml.etree' - imported by openpyxl.xml.functions (conditional)
missing module named openpyxl.tests - imported by openpyxl.reader.excel (optional)
missing module named lxml - imported by openpyxl.xml (delayed, optional)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,313 @@
('E:\\SelfSpace\\pythontool\\build\\消耗星星列表\\PYZ-00.pyz',
[('_compat_pickle',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_compat_pickle.py',
'PYMODULE'),
('_compression',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_compression.py',
'PYMODULE'),
('_py_abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_py_abc.py',
'PYMODULE'),
('_pydecimal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_pydecimal.py',
'PYMODULE'),
('_strptime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_strptime.py',
'PYMODULE'),
('_threading_local',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_threading_local.py',
'PYMODULE'),
('argparse',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\argparse.py',
'PYMODULE'),
('ast',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ast.py',
'PYMODULE'),
('base64',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\base64.py',
'PYMODULE'),
('bisect',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bisect.py',
'PYMODULE'),
('bz2',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bz2.py',
'PYMODULE'),
('calendar',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\calendar.py',
'PYMODULE'),
('contextlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\contextlib.py',
'PYMODULE'),
('contextvars',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\contextvars.py',
'PYMODULE'),
('copy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\copy.py',
'PYMODULE'),
('csv',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\csv.py',
'PYMODULE'),
('dataclasses',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\dataclasses.py',
'PYMODULE'),
('datetime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\datetime.py',
'PYMODULE'),
('decimal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\decimal.py',
'PYMODULE'),
('dis',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\dis.py',
'PYMODULE'),
('email',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\__init__.py',
'PYMODULE'),
('email._encoded_words',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_encoded_words.py',
'PYMODULE'),
('email._header_value_parser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_header_value_parser.py',
'PYMODULE'),
('email._parseaddr',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_parseaddr.py',
'PYMODULE'),
('email._policybase',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_policybase.py',
'PYMODULE'),
('email.base64mime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\base64mime.py',
'PYMODULE'),
('email.charset',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\charset.py',
'PYMODULE'),
('email.contentmanager',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\contentmanager.py',
'PYMODULE'),
('email.encoders',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\encoders.py',
'PYMODULE'),
('email.errors',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\errors.py',
'PYMODULE'),
('email.feedparser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\feedparser.py',
'PYMODULE'),
('email.generator',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\generator.py',
'PYMODULE'),
('email.header',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\header.py',
'PYMODULE'),
('email.headerregistry',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\headerregistry.py',
'PYMODULE'),
('email.iterators',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\iterators.py',
'PYMODULE'),
('email.message',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\message.py',
'PYMODULE'),
('email.parser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\parser.py',
'PYMODULE'),
('email.policy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\policy.py',
'PYMODULE'),
('email.quoprimime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\quoprimime.py',
'PYMODULE'),
('email.utils',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\utils.py',
'PYMODULE'),
('fnmatch',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\fnmatch.py',
'PYMODULE'),
('fractions',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\fractions.py',
'PYMODULE'),
('getopt',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\getopt.py',
'PYMODULE'),
('gettext',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gettext.py',
'PYMODULE'),
('gzip',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gzip.py',
'PYMODULE'),
('hashlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\hashlib.py',
'PYMODULE'),
('importlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\__init__.py',
'PYMODULE'),
('importlib._abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_abc.py',
'PYMODULE'),
('importlib._bootstrap',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_bootstrap_external.py',
'PYMODULE'),
('importlib.abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\abc.py',
'PYMODULE'),
('importlib.machinery',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\machinery.py',
'PYMODULE'),
('importlib.metadata',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\__init__.py',
'PYMODULE'),
('importlib.metadata._adapters',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_adapters.py',
'PYMODULE'),
('importlib.metadata._collections',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_collections.py',
'PYMODULE'),
('importlib.metadata._functools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_functools.py',
'PYMODULE'),
('importlib.metadata._itertools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_itertools.py',
'PYMODULE'),
('importlib.metadata._meta',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_meta.py',
'PYMODULE'),
('importlib.metadata._text',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_text.py',
'PYMODULE'),
('importlib.readers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\readers.py',
'PYMODULE'),
('importlib.resources',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\__init__.py',
'PYMODULE'),
('importlib.resources._adapters',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_adapters.py',
'PYMODULE'),
('importlib.resources._common',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_common.py',
'PYMODULE'),
('importlib.resources._itertools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_itertools.py',
'PYMODULE'),
('importlib.resources._legacy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_legacy.py',
'PYMODULE'),
('importlib.resources.abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\abc.py',
'PYMODULE'),
('importlib.resources.readers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\readers.py',
'PYMODULE'),
('importlib.util',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\util.py',
'PYMODULE'),
('inspect',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\inspect.py',
'PYMODULE'),
('ipaddress',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ipaddress.py',
'PYMODULE'),
('logging',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\logging\\__init__.py',
'PYMODULE'),
('lzma',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\lzma.py',
'PYMODULE'),
('numbers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\numbers.py',
'PYMODULE'),
('opcode',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\opcode.py',
'PYMODULE'),
('pathlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pathlib.py',
'PYMODULE'),
('pickle',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pickle.py',
'PYMODULE'),
('pprint',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pprint.py',
'PYMODULE'),
('py_compile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\py_compile.py',
'PYMODULE'),
('quopri',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\quopri.py',
'PYMODULE'),
('random',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\random.py',
'PYMODULE'),
('selectors',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\selectors.py',
'PYMODULE'),
('shutil',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\shutil.py',
'PYMODULE'),
('signal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\signal.py',
'PYMODULE'),
('socket',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\socket.py',
'PYMODULE'),
('statistics',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\statistics.py',
'PYMODULE'),
('string',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\string.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stringprep.py',
'PYMODULE'),
('subprocess',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\subprocess.py',
'PYMODULE'),
('tarfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tarfile.py',
'PYMODULE'),
('tempfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tempfile.py',
'PYMODULE'),
('textwrap',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\textwrap.py',
'PYMODULE'),
('threading',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\threading.py',
'PYMODULE'),
('tkinter',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\__init__.py',
'PYMODULE'),
('tkinter.commondialog',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\commondialog.py',
'PYMODULE'),
('tkinter.constants',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\constants.py',
'PYMODULE'),
('tkinter.messagebox',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\messagebox.py',
'PYMODULE'),
('tkinter.scrolledtext',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\scrolledtext.py',
'PYMODULE'),
('token',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\token.py',
'PYMODULE'),
('tokenize',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tokenize.py',
'PYMODULE'),
('tracemalloc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tracemalloc.py',
'PYMODULE'),
('typing',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\typing.py',
'PYMODULE'),
('urllib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
'PYMODULE'),
('urllib.parse',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\parse.py',
'PYMODULE'),
('zipfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\zipfile.py',
'PYMODULE')])

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,26 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named org - imported by copy (optional)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
missing module named 'org.python' - imported by pickle (optional)
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
missing module named resource - imported by posix (top-level)
missing module named grp - imported by subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional)
missing module named pwd - imported by posixpath (delayed, conditional, optional), subprocess (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional)
missing module named _posixsubprocess - imported by subprocess (conditional)
missing module named fcntl - imported by subprocess (optional)

File diff suppressed because it is too large Load Diff

Binary file not shown.

200
convert_cs_to_utf8.py Normal file
View File

@ -0,0 +1,200 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量将选定文件夹及其子文件夹中的所有 .cs 文件转换为 UTF-8 BOM也支持单文件转换
使用方式
1) 无参数直接运行默认使用路径 E:\WorkSpace\Meowment\Assets\GameMain\DataTables\DecorateCost.txt
2) 命令行传参python convert_cs_to_utf8.py "<目标文件夹路径或单个文件路径>"
- 传入文件夹会递归处理其中所有 .cs 文件
- 传入文件仅处理该文件不限扩展名
说明
- 会递归处理所有 .cs 文件当传入的是文件夹时
- 自动尝试多种常见编码进行解码最终以 UTF-8 BOM写回
- 已经是 UTF-8 且无 BOM 的文件会跳过
- 如原文件为 UTF-8 with BOM会移除 BOM 并写回为 UTF-8 BOM
"""
from __future__ import annotations
import os
import sys
from typing import Iterable, Tuple
# 为 Windows 提供图形化目录选择(可选)
try:
import tkinter as tk
from tkinter import filedialog, messagebox
_TK_AVAILABLE = True
except Exception:
_TK_AVAILABLE = False
CANDIDATE_ENCODINGS: Tuple[str, ...] = (
# 优先常见的 UTF 系列
"utf-8", "utf-8-sig",
"utf-16", "utf-16-le", "utf-16-be",
# 常见中文/东亚编码
"gb18030", "gbk", "big5", "shift_jis",
# 西文常见编码
"cp1252",
)
# 默认路径:当未提供命令行参数时使用
DEFAULT_TARGET_PATH = r"e:\WorkSpace\MeowMent_New\Assets\GameMain\Scripts\Hotfix\Entity\LevelItem.cs"
def read_bytes(path: str) -> bytes:
with open(path, "rb") as f:
return f.read()
def detect_and_decode(data: bytes) -> Tuple[str, str]:
"""尝试用多种编码解码,返回 (使用的编码, 文本)。失败则抛出 UnicodeDecodeError。
策略
- 如果有 UTF-8 BOM则优先用 utf-8-sig 解码能去除 BOM
- 依次尝试候选编码
- 若均失败抛出最后一次的异常
"""
# UTF-8 BOM 检测
if data.startswith(b"\xef\xbb\xbf"):
return "utf-8-sig", data.decode("utf-8-sig")
last_err: Exception | None = None
for enc in CANDIDATE_ENCODINGS:
try:
text = data.decode(enc)
return enc, text
except Exception as e:
last_err = e
continue
# 全部失败
if last_err:
raise last_err # type: ignore[misc]
raise UnicodeDecodeError("unknown", data, 0, 1, "cannot detect encoding")
def is_utf8_without_bom(data: bytes) -> bool:
"""粗略判断二进制是否为 UTF-8 且无 BOM。"""
if data.startswith(b"\xef\xbb\xbf"):
return False
try:
data.decode("utf-8")
return True
except UnicodeDecodeError:
return False
def iter_cs_files(root: str) -> Iterable[str]:
for dirpath, _dirnames, filenames in os.walk(root):
for name in filenames:
if name.lower().endswith(".cs"):
yield os.path.join(dirpath, name)
def convert_file_to_utf8(path: str) -> Tuple[bool, str | None]:
"""将单个文件转换为 UTF-8无 BOM
返回: (是否修改了文件, 错误消息或 None)
"""
try:
raw = read_bytes(path)
# 已是 UTF-8 且无 BOM -> 跳过
if is_utf8_without_bom(raw):
return False, None
# 尝试解码
used_enc, text = detect_and_decode(raw)
# 统一写为 UTF-8无 BOM
with open(path, "w", encoding="utf-8", newline="") as f:
f.write(text)
return True, None
except Exception as e:
return False, str(e)
def choose_directory_gui() -> str | None:
if not _TK_AVAILABLE:
return None
root = tk.Tk()
root.withdraw()
root.update()
path = filedialog.askdirectory(title="选择需要转换的根文件夹")
root.destroy()
if path:
return path
return None
def main(argv: list[str]) -> int:
# 1) 优先取命令行参数2) 否则使用默认路径
target_path = argv[1].strip() if (len(argv) >= 2 and argv[1].strip()) else DEFAULT_TARGET_PATH
# 收集待处理文件列表
files_to_process: list[str] = []
if os.path.isdir(target_path):
# 目录:仅处理 .cs 文件
files_to_process = list(iter_cs_files(target_path))
if not files_to_process:
print(f"目录下未找到 .cs 文件:{target_path}")
elif os.path.isfile(target_path):
# 单个文件:不限扩展名
files_to_process = [target_path]
else:
print(f"提供的路径无效:{target_path}")
return 1
total = 0
changed = 0
skipped = 0
errors = 0
error_list = []
print(f"开始处理: {target_path}")
for file_path in files_to_process:
total += 1
modified, err = convert_file_to_utf8(file_path)
if err:
errors += 1
error_list.append((file_path, err))
print(f"[错误] {file_path}: {err}")
else:
if modified:
changed += 1
print(f"[已转换] {file_path}")
else:
skipped += 1
# 可按需打印print(f"[已是UTF-8] {file_path}")
print("\n处理完成:")
print(f" 总计 .cs 文件: {total}")
print(f" 已转换为 UTF-8无 BOM: {changed}")
print(f" 已跳过(本就是 UTF-8 无 BOM: {skipped}")
print(f" 发生错误: {errors}")
# 如在 GUI 环境,弹窗汇总
# 若通过 GUI 运行且未提供参数,可弹窗汇总(此脚本现在默认有固定路径,弹窗仅在 GUI 手动改造时有效)
if _TK_AVAILABLE and (len(argv) == 1):
try:
msg = (f"总计: {total}\n"
f"转换: {changed}\n"
f"跳过: {skipped}\n"
f"错误: {errors}")
messagebox.showinfo("转换完成", msg)
except Exception:
pass
# 可选:将错误列表打印到结尾便于查看
if error_list:
print("\n错误详情:")
for p, e in error_list:
print(f"- {p}: {e}")
return 0 if errors == 0 else 2
if __name__ == "__main__":
sys.exit(main(sys.argv))

504
de.csv Normal file
View File

@ -0,0 +1,504 @@
Key (do not touch),Default,Translation
INVALID_TR,%%this should not be displayed%%,%%this should not be displayed%%
ABOUT,About,Über
LATEST_RELEASE,Latest release,Neuste Version
OFS_LOG_OUTPUT,OFS Log Output,OFS Log Output
ADD_EDIT_ACTIONS,Add/Edit actions,Aktionen einfügen / editieren
ADD_EDIT_ACTION,Add/Edit action,Aktion einfügen / editieren
ADD_ACTION,Add action,Aktion einfügen
REMOVE_ACTIONS,Remove actions,Aktionen entfernen
REMOVE_ACTION,Remove action,Aktion entfernen
MOUSE_MOVED_ACTIONS,Mouse moved actions,Mit der Maus bewegte Aktionen
ACTIONS_MOVED,Actions moved,Aktionen bewegt
CUT_SELECTION,Cut selection,Auswahl ausschneiden
REMOVE_SELECTION,Remove selection,Auswahl entfernen
PASTE_SELECTION,Paste selection,Auswahl einfügen
EQUALIZE,Equalize,Angleichen
INVERT,Invert,Invertieren
ISOLATE,Isolate,Isolieren
TOP_POINTS,Top points,Obere Punkte
MID_POINTS,Mid points,Mittlere Punkte
BOTTOM_POINTS,Bottom points,Untere Punkte
GENERATE_ACTIONS,Generate actions,Erzeuge Aktion
FRAME_ALIGN,Frame align,Frame angleichen
RANGE_EXTEND,Range extend,Reichweite erhöhen
REPEAT_STROKE,Repeat stroke,Wiederhole stroke
MOVE_TO_CURRENT_POSITION,Move to current position,Bewege zur aktuellen Position
SIMPLIFY,Simplify,Vereinfachen
LUA_SCRIPT,Lua script,Lua script
REDO_STACK,Redo stack,Stapel wiederherstellen
UNDO_STACK,Undo stack,Stapel rückgängig machen
UNDO_REDO_HISTORY,Undo/Redo history,Rückgängig/Wiederherstellen Verlauf
T_CODE,T-Code,T-Code
PORT,Port,Port
OPEN_PORT,Open port,Öffne Port
LIMITS,Limits,Limits
LINEAR_LIMITS,Linear limits,Lineare Limits
ROTATION_LIMITS,Rotation limits,Rotations Limits
VIBRATION_LIMITS,Vibration limits,Vibrations Limits
GLOBAL_SETTINGS,Global settings,Globale Einstellungen
DELAY,Delay,Verzögerung
CONTROLLER_BUTTON_A,A / X,A / X
CONTROLLER_BUTTON_B,B / Circle,B / Kreis
CONTROLLER_BUTTON_X,X / Square,X / Viereck
CONTROLLER_BUTTON_Y,Y / Triangle,Y / Dreieck
CONTROLLER_BUTTON_BACK,Back / Share,Zurück / Teilen
CONTROLLER_BUTTON_GUIDE,Guide,Anleitung
CONTROLLER_BUTTON_START,Start,Start
CONTROLLER_BUTTON_LEFTSTICK,Leftstick,Linker Stick
CONTROLLER_BUTTON_RIGHTSTICK,Rightstick,Rechter Stick
CONTROLLER_BUTTON_LEFTSHOULDER,Leftshoulder,Linke Schultertaste
CONTROLLER_BUTTON_RIGHTSHOULDER,Rightshoulder,Rechte Schultertaste
CONTROLLER_BUTTON_DPAD_UP,DPAD Up,DPAD oben
CONTROLLER_BUTTON_DPAD_DOWN,DPAD Down,DPAD unten
CONTROLLER_BUTTON_DPAD_LEFT,DPAD Left,DPAD links
CONTROLLER_BUTTON_DPAD_RIGHT,DPAD Right,DPAD rechts
CONTROLLER_NOT_SET,- Not set -,- Nicht gesetzt -
KEY_MOD_CTRL,Ctrl,Strg
KEY_MOD_ALT,Alt,Alt
KEY_MOD_SHIFT,Shift,Shift
KEY_ALREADY_IN_USE,Key is in use,Taste ist bereits in Benutzung
KEY_ALREADY_IN_USE_MSG,Key already bound for [%s],Taste bereits belegt für [%s]
BUTTON_ALREADY_IN_USE,Button is in use,Taste ist bereits in Benutzung
BUTTON_ALREADY_IN_USE_MSG,Button already bound for [%s],Taste bereits belegt für [%s]
DESCRIPTION,Description,Beschreibung
KEYBOARD,Keyboard,Tastatur
ACTIVE,Active,Aktiv
KEY_NOT_SET,- Not set -,- Nicht gesetzt -
CHANGE_KEY,Change key,Ändere Taste
CHANGE_KEY_MSG,"Press any key...
Escape to clear.","Drücke eine Taste...
Escape zum Löschen."
PASSIVE_BINDING_TXT1,Here modifiers can be configured which change certain behaviour.,"Hier können Modifikatoren konfiguriert werden, die bestimmte Verhalten ändern."
PASSIVE_BINDING_TXT2,"You can only use Shift, Ctrl & Alt.","Du kannst nur Shift, Strg & Alt benutzen."
KEYS,Keys,Tasten
BINDINGS,Bindings,Tastenzuweisungen
BINDING_TXT1,"You can use CTRL, SHIFT & ALT as modifiers.","Du kannst STRG, SHIFT & ALT als Modifizierer benutzen."
BINDING_TXT2,Only controller buttons can be bound. The DPAD directions count as a buttons.,Nur Controller Tasten können gesetzt werden. Die DPAD Richtungen fungieren als Tasten.
BINDING_TXT3,The configuration gets saved everytime a change is made.,"Änderungen werden gespeichert, sobald eine Änderung durchgeführt wird."
BINDING_TXT4,"If you wan't to revert to the defaults, you'll have to delete the config.","Wenn die zu den Standarteinstellungen zurückkehren möchtest, musst du die Config löschen."
FILTER,Filter,Filter
MODIFIERS,Modifiers,Modifizierer
ACTION,Action,Aktion
CONTROLLER,Controller,Controller
IGNORE_REPEATS,Ignore repeats,Ignoriere Wiederholungen
CHANGE_BUTTON,Change button,Ändere Taste
CHANGE_BUTTON_MSG,"Press any button...
Escape to clear.","Drücke eine Taste...
Escape zum Löschen."
RUNNING_TASK,Running task,Laufender Prozess
THIS_MAY_TAKE_A_WHILE,This may take a while...,Das könnte eine Zeit dauern...
OPTIONS,Options,Optionen
AUTO_SCROLL,Auto-scroll,Auto-scroll
CLEAR,Clear,Beseitigen
COPY,Copy,Kopiere
USED,Used,Benutzt
ALLOCATED,Allocated,Zugewiesen
SCRIPTS,Scripts,Scripts
RENDERING,Rendering,Rendering
SHOW_ACTIONS,Show actions,Zeige Aktionen
SPLINE_MODE,Spline mode,Kurven-Modus
SHOW_VIDEO_POSITION,Show video position,Zeige Videopostition
WAVEFORM,Waveform,Waveform
SETTINGS,Settings,Einstellungen
SCALE,Scale,Skalierung
COLOR,Color,Farbe
ENABLE_WAVEFORM,Enable waveform,Aktiviere Waveform
MIN_INT_FMT,Min: %d,Min: %d
MAX_INT_FMT,Max: %d,Max: %d
TCODE_TICKRATE,Tickrate (Hz),Tickrate (Hz)
SPLINE,Spline,Kurve
SPLINE_TOOLTIP,Smooth motion instead of linear.,"Weiche Bewegung, statt linearer."
REMAP,Remap,Neu belegen
REMAP_TOOLTIP,"Remap script to use the full range.
i.e. scripts using the range 10 to 90 become 0 to 100.","Remap Script, damit es die volle Reichweite benutzt.
Z.b. Scripts, die die Reichweite 10 bis 90 benutzen, werden zu 0 bis100."
DELAY_TOOLTIP,"Negative: Backward in time.
Positive: Forward in time.","Negativ: Zurück in der Zeit.
Postiv: Vorwärts in der Zeit."
OUTPUTS,Outputs,Ausgaben
YOU_CAN_RIGHT_CLICK_SLIDERS_TOOLTIP,You can right click sliders.,Du kannst die Slider rechtsklicken.
REBALANCE,Rebalance,Rebalance
REBALANCE_TOOLTIP,Balance around 500 even with unevenly spread limits.,"Balance um 500, selbst mit ungleichen Breite-Limits."
GAMEPAD_ONLY,only,nur
SHOW_VIDEO_POSITION_TOOLTIP,"(Frame overlay only)
Shows a red line where the current frame is.
More of a debugging feature.","(Nur Frame Overlay)
Zeigt eine Rote Linie, wo sich der aktuelle Frame befindet.
Eher ein debugging Feature."
PROCESSING_AUDIO,Processing audio...,Verarbeite Audio...
UPDATE_WAVEFORM,Update waveform,Aktualisiere Waveform
POSITIONS,Positions,Positionen
LOOP_A_SET,Loop A set,Schleife bei A setzen (Loop-Modus)
LOOP_B_SET,Loop B set,Schleife bei B setzen (Loop-Modus)
LOCK,Lock,Sperren
CLICK_TO_ENABLE_VIDEO,Click to enable video,"Drücke, um Video zu aktivieren."
LOOP_CLEARED,Loop cleared,Wiederholung gelöscht.
VIDEOPLAYER,Player,Player
SPEED,Speed,Geschwindigkeit
TIMELINE,Timeline,Zeitlinie
TIME,Time,Zeit
CONTROLS,Controls,Steuerung
TIMELINE_SECONDS,seconds,Sekunden
TASK_EXPORTING_CLIPS,Exporting clips,Exportiere Clips
PROJECT,Project,Projekt
MEDIA,Media,Medien
CHANGE_DEFAULT_LOCATION,Change default location,Ändere Standardverzeichnis
CHANGE_LOCATION,Change location,Ändere Verzeichnis
SCRIPTING_MODE,Scripting mode,Scripting Modus
DEFAULT_MODE,Default,Standard
ALTERNATING_MODE,Alternating,Abwechslend (Alternating)
DYNAMIC_INJECTION_MODE,Dynamic injection,Dynamische Injektion (Dynamic injection)
RECORDING_MODE,Recording,Aufnehmen
SCRIPTING_OVERLAY,Scripting overlay,Scripting overlay
FRAME_OVERLAY,Frame,Frame
TEMPO_OVERLAY,Tempo,Tempo
EMPTY_OVERLAY,None,nichts
OFFSET_MS,Offset (ms),Versetzt (ms)
OFFSET_TOOLTIP,"Applies an offset to actions inserted while the video is playing.
- : inserts earlier
+ : inserts later","Wende eine Versetzung an, bei eingefügten Aktionen, während das Video spielt.
- : füge früher ein
+ : füge später ein"
MIRROR_MODE,Mirror mode,Spiegelmodus (Mirror Modus)
MIRROR_MODE_TOOLTIP,Mirrors add/edit/remove action across all loaded scripts.,Füge ein/editiere/entferne Spiegelungs-Aktionen (Mirros) bei allen geladenen Scripts.
DI_TARGET_SPEED,Target speed (units/s),Ziel Geschwindigkeit (Einheiten/s)
DI_UP_DOWN_BIAS,Up/Down speed bias,Erhöhe/Verringe Geschwindigkeits-Bias
TOP,Top,Oben
BOTTOM,Bottom,Unten
NEXT_POINT,Next point,Nächster Punkt
NEXT_POINT_AT_FMT,Next point is at %d,Nächster Punkt ist bei %d
NEXT_POINT_IS_FMT,Next point is %s,Nächster Punkt ist %s
INVERTED,inverted,umgekehrt
NOT_INVERTED,not inverted,nicht umgekehrt
FIXED_RANGE,Fixed range,Fixierte Reichweite
CONTEXT_SENSITIVE,Context sensitive,Sensibler Inhalt
CONTEXT_SENSITIVE_TOOLTIP,Alternates based on the previous action.,Wechsel basierend auf der vorherigen Aktion.
MODE,Mode,Modus
MOUSE,Mouse,Maus
CONTROLLER_DEADZONE,Controller deadzone,Controller deadzone
DEADZONE,Deadzone,Deadzone
CENTER,Center,Mitte
TWO_AXES,Two axes,Zwei Axen
TWO_AXES_TOOLTIP,"Recording pitch & roll at once.
Using Simulator 3D settings.
Only works with a controller.","Nehme pitch & roll gleichzeitig auf.
Benutze 3D Simulator Einstellungen.
Funktioniert nur mit einem Controller."
RECORD_ON_PLAY,Record on play,Aufnehmen beim Abspielen
TWO_AXES_AXES,X / Y,X / Y
POSITION,Position,Position
RECORDING_ACTIVE,Recording active,Aufnahme aktiv
RECORDING_PAUSED,Recording paused,Aufnahme pausiert
STATISTICS,Statistics,Statistiken
ACTION_EDITOR,Action editor,Aktionseditor
DYNAMIC_BINDING_GROUP,Dynamic,Dynamisch
ACTIONS_BINDING_GROUP,Actions,Aktionen
CORE_BINDING_GROUP,Core,Core
NAVIGATION_BINDING_GROUP,Navigation,Navigation
UTILITY_BINDING_GROUP,Utility,Utility
MOVING_BINDING_GROUP,Moving,Bewegen
SPECIAL_BINDING_GROUP,Special,Spezial
VIDEOPLAYER_BINDING_GROUP,Video player,Video player
EXTENSIONS_BINDING_GROUP,Extensions,Erweiterungen
CONTROLLER_BINDING_GROUP,Controller,Controller
ACTION_REMOVE_ACTION,Remove action,Entferne Aktion
ACTION_ACTION_0,Action at 0,Aktion bei 0
ACTION_ACTION_10,Action at 10,Aktion bei 10
ACTION_ACTION_20,Action at 20,Aktion bei 20
ACTION_ACTION_30,Action at 30,Aktion bei 30
ACTION_ACTION_40,Action at 40,Aktion bei 40
ACTION_ACTION_50,Action at 50,Aktion bei 50
ACTION_ACTION_60,Action at 60,Aktion bei 60
ACTION_ACTION_70,Action at 70,Aktion bei 70
ACTION_ACTION_80,Action at 80,Aktion bei 80
ACTION_ACTION_90,Action at 90,Aktion bei 90
ACTION_ACTION_100,Action at 100,Aktion bei 100
ACTION_SAVE_PROJECT,Save project,Speichere Projekt
ACTION_QUICK_EXPORT,Quick export,Schnelles exportieren
ACTION_SYNC_TIME_WITH_PLAYER,Sync time with player,Synchronisiere Zeit mit Player
ACTION_CYCLE_FORWARD_LOADED_SCRIPTS,Cycle forward loaded scripts,Schalte vorwärts zum gelandenen Script
ACTION_CYCLE_BACKWARD_LOADED_SCRIPTS,Cycle backward loaded scripts,Schalte zurück zum gelandenen Script
ACTION_PREVIOUS_ACTION,Previous action,Vorherige Aktion
ACTION_NEXT_ACTION,Next action,Nächste Aktion
ACTION_PREVIOUS_ACTION_MULTI,Previous action (multi),Vorherige Aktion (multi)
ACTION_NEXT_ACTION_MULTI,Next action (multi),Nächste Aktion (multi)
ACTION_PREV_FRAME,Previous frame,Vorheriger Frame
ACTION_NEXT_FRAME,Next frame,Nächster Frame
ACTION_FAST_STEP,Fast step,Schnelles Vorwärts
ACTION_FAST_BACKSTEP,Fast backstep,Schnelles Zurück
ACTION_UNDO,Undo,Rückgängig
ACTION_REDO,Redo,Wiederherstellen
ACTION_COPY,Copy,Kopieren
ACTION_PASTE,Paste,Einfügen
ACTION_CUT,Cut,Ausschneiden
ACTION_PASTE_EXACT,Paste exact,Füge exakt ein
ACTION_SELECT_ALL,Select all,Wähle alles aus
ACTION_DESELECT_ALL,Deselect all,Deselektiere alles
ACTION_SELECT_ALL_LEFT,Select all left,Wähle alles Linke aus
ACTION_SELECT_ALL_RIGHT,Select all right,Wähle alles Rechte aus
ACTION_SELECT_TOP,Select top points,Wähle Top Punke aus
ACTION_SELECT_BOTTOM,Select bottom points,Wähle Untere Punkte aus
ACTION_SELECT_MID,Select middle points,Wähle Mittlere Punkte aus
ACTION_TOGGLE_MIRROR_MODE,Toggle mirror mode,Schalte Spiegelmodus um
ACTION_SAVE_FRAME,Save frame as image,Speichere Frame als Bild
ACTION_CYCLE_SUBTITLES,Cycle subtitles,Wechsle Untertitel
ACTION_TOGGLE_FULLSCREEN,Toggle fullscreen,Schalte Vollbild um
ACTION_MOVE_UP_10,Move actions +10 up,Bewege Aktion +10 nach oben
ACTION_MOVE_DOWN_10,Move actions -10 down,Bewege Aktion - 10 nach unten
ACTION_MOVE_UP_5,Move actions +5 up,Bewege Aktion + 5 nach oben
ACTION_MOVE_DOWN_5,Move actions -5 down,Bewege Aktion - 5 nach unten
ACTION_MOVE_ACTIONS_LEFT_SNAP,Move actions left with snapping,Bewege Aktion nach links mit snapping
ACTION_MOVE_ACTIONS_RIGHT_SNAP,Move actions right with snapping,Bewege Aktionen nach rechts mit snapping
ACTION_MOVE_ACTIONS_LEFT,Move actions left,Bewege Aktionen nach links
ACTION_MOVE_ACTIONS_RIGHT,Move actions right,Bewege Aktionen nach rechts
ACTION_MOVE_ACTIONS_UP,Move actions up,Bewege Aktionen nach oben
ACTION_MOVE_ACTIONS_DOWN,Move actions down,Bewege Aktionen nach unten
ACTION_MOVE_TO_CURRENT_POSITION,Move to current position,Bewege zur aktuellen Position
ACTION_EQUALIZE_ACTIONS,Equalize actions,Gleiche Aktionen an
ACTION_INVERT_ACTIONS,Invert actions,Kehre Aktionen um
ACTION_ISOLATE_ACTION,Isolate action,Isoliere Aktionen
ACTION_REPEAT_STROKE,Repeat stroke,Wiederhole Stroke
ACTION_TOGGLE_PLAY,Play / Pause,Abspielen / Pause
ACTION_REDUCE_PLAYBACK_SPEED,Playback speed -10%,Abspielgeschwindigkeit -10%
ACTION_INCREASE_PLAYBACK_SPEED,Playback speed +10%,Abspielgeschwindigkeit +10%
ACTION_GO_TO_START,Go to the start,Gehe zu Start
ACTION_GO_TO_END,Go to the end,Gehe zu Ende
ACTION_RELOAD_ENABLED_EXTENSIONS,Reload enabled extensions,Lade aktivierte Erweiterungen
ACTION_TOGGLE_CONTROLLER_NAV,Toggle controller navigation,Schalte Controller Navigation um
ACTION_SEEK_FORWARD_1,Forward 1 second,1 Sekunde vorwärts
ACTION_SEEK_BACKWARD_1,Backward 1 second,1 Sekunden zurück
ACTION_ADD_ACTION_CONTROLLER,Add action,Füge Aktion ein
ACTION_TOGGLE_RECORDING_MODE,Toggle recording mode,Schalte Aufnahmemodus um
ACTION_CONTROLLER_SELECT,Controller selection,Controller Auswahl
ACTION_SET_PLAYBACK_SPEED,Set current playback speed,Setze aktuelle Wiedergabegeschwindigkeit
PASSIVE_GROUP_TIMELINE,Point timeline,Script Zeitlinie
PASSIVE_GROUP_SIMULATOR,Simulator,Simulator
MOD_MOVE_OR_ADD_POINT,Click drag/add point in the timeline,Klicke und ziehe/füge Punkt in Zeitlinie ein
MOD_CLICK_SIM_ADD_PONT,Click simulator to add a point,"Klicke Simulator, um Punkt einzufügen"
PROJECT_HAS_UNSAVED_EDITS,Project has unsaved edits,Projekt hat nicht gespeicherte Änderungen
UNSAVED_EDITS_MSG,The current project has unsaved edits.,Das aktuelle Projekt hat nicht gespeicherte Änderungen.
UNSAVED_CHANGES,Unsaved changes,Nicht gespeicherte Änderungen
UNSAVED_CHANGES_MSG,Do you want to save and exit?,Möchtest du speichern und beenden?
FILE_NOT_FOUND,File not found,Datei nicht gefunden
COULDNT_FIND_FILE,Couldnt find file,Konnte Datei nicht finden
OFS_FAILED_TO_IMPORT,OpenFunscripter failed to import.,OpenFunscripter konnte nicht importieren.
OFS_FAILED_TO_IMPORT_MSG,Failed to import,Importieren fehlgeschlagen
FAILED_TO_LOAD,Failed to load,Laden fehlgeschlagen
FAILED_TO_LOAD_MSG,The project failed to load.,Das Projekt konnte nicht geladen werden.
FAILED_TO_FIND_VIDEO,Failed to find video,Konnte Video nicht finden
FAILED_TO_FIND_VIDEO_MSG,"The video was not found.
Please pick the correct video.","Das Video wurde nicht gefunden.
Wähle bitte das richtige Video aus."
CHOOSE_OUTPUT_DIR,Choose output directory,Wähle Ausgansverzeichnis
PICK_DIFFERENT_MEDIA,Pick different media,Wähle anderes Medium
FILE,File,Datei
OPEN_PROJECT,Open project,Öffne Projekt
SAVE,Save,Speichern
CLOSE_PROJECT,Close project,Schließe Projekt
WRONG_FILE,Wrong file,Falsche Datei
WRONG_FILE_MSG,The file isnt a project file.,Diese Datei ist keine Projekt-Datei
IMPORT_VIDEO_SCRIPT,Import video/script,Video/Script importieren
RECENT_FILES,Recent files,Kürzliche Datein
NO_RECENT_FILES,No recent files,Keine kürzliche Datein
SAVE_PROJECT,Save project,Speichere Projekt
EXPORT_MENU,Export...,Exportiere...
QUICK_EXPORT,Quick export,Schnelles Exportieren
QUICK_EXPORT_TOOLTIP,Exports all scripts as .funscript in their default paths.,Exportiere alle Scripts als.funscript in ihren Standardpfaden.
EXPORT_ACTIVE_SCRIPT,Export active script,Exportiere aktives Script.
EXPORT_ALL,Export all,Exportiere alles
AUTO_BACKUP_TIMER_FMT,Auto Backup in %d seconds,Auto Backup in %d Sekunden
AUTO_BACKUP,Auto Backup,Auto Backup
OPEN_BACKUP_DIR,Open backup directory,Öffne Backupordner
CONFIGURE,Configure,Konfiguriere
ADD_MENU,Add...,Füge hinzu...
ADD_SHORTCUTS,Shortcuts,Tastenkürzel
ADD_NEW,Add new,Füge neu ein
ADD_NEW_FUNSCRIPT,Add new funscript,Füges neues funscript ein
ADD_EXISTING,Add existing,Füge bestehendes ein
ADD_EXISTING_FUNSCRIPTS,Add existing funscripts,Füge bestehendes funscript ein
REMOVE_SCRIPT_CONFIRM_MSG,"If the script wasnt previously exported, this cant be reverted.
Continue?","Falls das Script zuvor nicht exportiert wurde, kann dies nicht rückgängig gemacht werden.
Fortsetzen?"
REMOVE,Remove,Entferne
REMOVE_SCRIPT,Remove script,Entferne Script
EDIT,Edit,Editiere
SAVE_FRAME_AS_IMAGE,Save frame as image,Speichere Frame als Bild
OPEN_SCREENSHOT_DIR,Open screenshot directory,Öffne Screenshotordner
SAVE_HEATMAP,Save heatmap,Speichere heatmap
UNDO,Undo,Rückgängig
REDO,Redo,Wiederholen
CUT,Cut,Aussschneiden
PASTE,Paste,Einfügen
SELECT,Select,Auswählen
SELECT_ALL,Select all,Wähle alles aus
DESELECT_ALL,Deselect all,Wähle alles ab
SPECIAL,Special,Speziall
SELECT_ALL_LEFT,Select all left,Wähle alles Linke aus
SELECT_ALL_RIGHT,Select all right,Wähle alles Rechte aus
SET_SELECTION_START,Set selection start,Wähle Auswahl Anfang
SET_SELECTION_END,Set selection end,Wähle Auswahl Ende
TOP_POINTS_ONLY,Top points only,Nur obere Punke
MID_POINTS_ONLY,Mid points only,Nur mittlere Punkte
BOTTOM_POINTS_ONLY,Bottom points only,Nur untere Punkte
BOOKMARKS,Bookmarks,Lesezeichen
EXPORT_CLIPS,Export clips,Exportiere Clips
EXPORT_CLIPS_TOOLTIP,Export smaller clips based on bookmarks.,"Exportiere kürzere Clips, basierend auf Lesezeichen."
NAME,Name,Name
ADD_BOOKMARK,Add bookmark,Füge Lesezeichen ein
CREATE_INTERVAL_FOR_FMT,"Create interval for ""%s""","Erstelle Intervall für ""%s"""
GO_TO_MENU,Go to...,Gehe zu...
NO_BOOKMARKS,No bookmarks,Keine Lesezeichen
ALWAYS_SHOW_LABELS,Always show labels,Zeige immer Bezeichnung
DELETE_ALL_BOOKMARKS,Delete all bookmarks,Lösche alle Lesezeichen
VIEW_MENU,View,Zeige
SIMULATOR_3D,Simulator 3D,3D Simulator
METADATA,Metadata,Metadata
DRAW_VIDEO,Draw video,Zeige Video
RESET_VIDEO_POS,Reset video position,Setze Videoposition zurück
VIDEO_MODE,Video mode,Videomodus
VIDEO_MODE_FULL,Full,Voll
VIDEO_MODE_LEFT_PANE,Left pane,Linke Seite
VIDEO_MODE_RIGHT_PANE,Right pane,Rechte Seite
VIDEO_MODE_TOP_PANE,Top pane,Obere Seite
VIDEO_MODE_BOTTOM_PANE,Bottom pane,Untere Seite
VIDEO_MODE_VR,VR,VR
DEBUG,Debug,Debug
METRICS,Metrics,Metrik
LOG_OUTPUT,Log output,Log Output
FULLSCREEN,Fullscreen,Vollbild
PREFERENCES,Preferences,Einstellungen
REPEAT_RATE,Repeat rate,Wiederholungsrate
CONTROLLER_CONNECTED,Controller connected!,Controller verbunden!
EXTENSIONS_MENU,Extensions,Erweiterungen
DEV_MODE,Developer mode,Entwicklermodus
SHOW_LOGS,Show logs,Zeige Logs
DEV_MODE_TOOLTIP,Enable extra functionality for extension developement.,Erlaube extra Funktionen für Erweiterungsentwicklung
EXTENSION_DIR,Extension directory,Erweiterungsverzeichnis
ENABLED,Enabled,Aktiviert
SHOW_WINDOW,Show window,Zeige Fenster
OPEN_DIRECTORY,Open directory,Öffne Verzeichnis
NAVIGATION,Navigation,Navigation
SCRIPTING,Scripting,Scripting
UNSAVED_CHANGES_FMT,unsaved changes %d minutes ago,Ungespeichterte Änderungen seit %d Minuten
METADATA_EDITOR,Metadate editor,Metadata Editor
TITLE,Title,Titel
DURATION,Duration,Dauer
CREATOR,Creator,Ersteller
URL,Url,Url
VIDEO_URL,Video url,Video url
NOTES,Notes,Notizen
LICENSE,License,Linzenz
FREE,Free,Kostenlos
PAID,Paid,Kostenpflichtig
NONE,None,Keine
TAGS,Tags,Schlagwörter
ADD,Add,Füge ein
PERFORMERS,Performers,Darsteller
SAVE_TEMPLATE,Save template,Speichere Vorlage
SAVE_TEMPLATE_TOOLTIP,Saves all current values as defaults for later.,Speichere alle aktuellen Werte als Standard für später.
GIT_COMMIT,Commit,Commit
INTERVAL,Interval,Intervall
CLOSE_WITHOUT_SAVING,Close without saving?,Schließen ohne zu speichern?
CLOSE_WITHOUT_SAVING_MSG,The current project has unsaved changes do you want to close it without saving?,Das aktuelle Projekt hat ungespeicherte Änderungen. Willst du es ohne zu speichern schließen?
CONFIGURATION,Configuration,Konfiguration
RESET,Reset,Zurücksetzen
MOVE,Move,Bewege
DISTANCE,Distance,Distanz
GLOBAL_YAW,Global yaw,Globales yaw
GLOBAL_PITCH,Global pitch,Globales pitch
BOX,Box,Box
CONTAINER,Container,Container
TWIST,Twist,Twist
ROLL_DEG,Roll deg,Roll Grad
PITCH_DEG,Pitch deg,Pitch Grad
TWIST_DEG,Twist deg,Twist Grad
ROLL,Roll,Roll
PITCH,Pitch,Pitch
YAW,Yaw,Yaw
INSERT_CURRENT_POSITION,Insert current position,Füge aktuelle Position ein
SCROLL_PERCENT,Scroll (%),Scroll (%)
SCROLL_PERCENT_TOOLTIP,You can use the mousewheel on the sliders above.,Du kannst das Mausrad für die oberen Regler benutzen.
EXTENSION_LOG_OUTPUT,Extension log output,Erweiterungen log output
ERROR_STR,Error,Fehler
TRY_RELOADING,Try reloading,Versuche neu laden
RELOAD,Reload,Lade neu
BPM,BPM,BPM
OFFSET,Offset,Versetzung (Offset)
SNAP,Snap,Snap
UNKNOWN_ERROR,unknown error,Unbekannter Fehler
FFMPEG_WAS_NOT_FOUND_MSG,"ffmpeg.exe was not found.
Do you want to download it?","ffmpeg.exe wurde nicht gefunden.
Möchtest du es herunterladen?"
BINDABLE_FUNCTIONS,Bindable functions,"Funktionen, die als Tastenkürzel gesetzt werden können"
YES,Yes,Ja
FFMPEG_FAILED_TO_DOWNLOAD_MSG,Failed to download from https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip,Fehler beim Herunterladen von https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip
DONE,Done,Fertig
DONE_MSG,ffmpeg.exe was successfully extracted.,ffmpeg.exe wurde erfolgreiche extrahiert.
EXTRACT_FAIL,Failed to extract ffmpeg.exe.,Fehler beim Extrahieren von fffmpeg.exe.
EXTRACT_FAIL_MSG,"Extracting uses tar.exe.
It will fail if it's not on your system.","Extrahieren benutzt tar.exe.
Es wird nicht funktionieren, wenn es nicht installiert ist."
DOWNLOAD_FFMPEG,Download ffmpeg?,Download ffmpeg?
TEMPO_WHOLE_MEASURES,whole measures,Ganze Maße
TEMPO_2ND_MEASURES,2nd measures,2te Maße
TEMPO_4TH_MEASURES,4th measures,4te Maße
TEMPO_8TH_MEASURES,8th measures,8te Maße
TEMPO_12TH_MEASURES,12th measures,12te Maße
TEMPO_16TH_MEASURES,16th measures,16te Maße
TEMPO_24TH_MEASURES,24th measures,24ste Maße
TEMPO_32ND_MEASURES,32nd measures,32ste Maße
TEMPO_48TH_MEASURES,48th measures,48ste Maße
TEMPO_64TH_MEASURES,64th measures,64ste Maße
LOAD_CONFIG,Load config,Lade Config
SAVE_CONFIG,Save config,Speichere Config
SAVE_SIMULATOR_CONFIG,Save simulator configuration,Speichere Simulator Konfiguration
SAVE_SIMULATOR_CONFIG_MSG,"Do you want do save the current config?
This will override any existing default config.","Möchstest du die aktuelle Config speichern?
Dies wird sämtliche existierenden Standard Configs überschreiben."
LINES,Lines,Linien
TEXT,Text,Text
FRONT,Front,Vorne
BACK,Back,Hinten
BORDER,Border,Rahmen
INDICATOR,Indicator,Indikator
LINE,Line,Linie
WIDTH,Width,Weite
OPACITY,Opacity,Deckkraft
EXTRA_LINES,Extra lines,Extra Linien
VANILLA,Vanilla,Vanilla
SHOW_POSITION,Show position,Zeige Position
VANILLA_TOOLTIP,The original simulator from day one.,Der originale Simulator von der ersten Version.
RESET_TO_DEFAULTS,Reset to defaults,Setze zu Standard zurück
SIMULATOR,Simulator,Simulator
APPLICATION,Application,Applikation
DARK_MODE,Dark mode,Dunkler Modus
LIGHT_MODE,Light mode,Heller Modus
PREFERENCES_TXT,"Higher frame rate makes OFS feel ""snappier"" because input gets processed more frequently.","Höhere Frameraten lassen OFS ""snappier"" anfühlen, weil Eingaben häufiger verarbeitet werden."
VSYNC,Vsync,Vsync
VSYNC_TOOLTIP,"Limits frame rate to the refresh rate of the monitor.
Frame limit is ignored.","Limitiert Frame Rate auf die Wiederholungsrate des Monitors.
Frame Limitierung wird ignoriert."
FRAME_LIMIT,Frame limit,Frame Limitierung
FRAME_LIMIT_TOOLTIP,This limits the frame rate OFS is running at.,"Das limitiert die Frame Rate, in welcher OFS läuft."
FONT,Font,Schrift
CHANGE,Change,Ändere
CHOOSE_FONT,Choose font,Wähle Schrift
DEFAULT_FONT,Default font,Standardschrift
FONT_SIZE,Font size,Schriftgröße
FORCE_HW_DECODING,Force hardware decoding (Requires program restart),Erzwinge Hardwarebeschleunigung (Erfordert Neustart)
FORCE_HW_DECODING_TOOLTIP,May cause crashes on some systems.,Kann bei einigen System abstürzen.
FAST_FRAME_STEP,Fast frame step,Schneller Frame Step
FAST_FRAME_STEP_TOOLTIP,Amount of frames to skip with fast step.,Wieviel Frames beim schnellen Frame Step geskipt werden.
SHOW_METADATA_DIALOG_ON_NEW_PROJECT,Show metadata dialog on new project,Zeige Metadata Fenster bei einem neuen Projekt.
FUNCTIONS_RANGE_EXTENDER,Range extender,Reichweitenverlängerer
FUNCTIONS_SIMPLIFY,Simplify (Ramer-Douglas-Peucker),Vereinfache (Ramer-Douglas-Peucker)
RANGE,Range,Reichweite
RANGE_EXTENDER_TXT,Select atleast 5 actions to extend.,Wähle mindestens 5 Aktionen zum Verlängern.
EPSILON,Epsilon,Epsilon
SIMPLIFY_TXT,Select atleast 5 actions to simplify.,Wähle mindestens 5 Aktionen zum Vereinfachen.
SPECIAL_FUNCTIONS,Special functions,Spezielle Funktionen
MEMORY_USAGE,Memory usage,Speichergebrauch
UPDATE,Update,Update
SLOWEST,slowest,langsamste
LANGUAGE,Language,Sprache
1 Key (do not touch) Default Translation
2 INVALID_TR %%this should not be displayed%% %%this should not be displayed%%
3 ABOUT About Über
4 LATEST_RELEASE Latest release Neuste Version
5 OFS_LOG_OUTPUT OFS Log Output OFS Log Output
6 ADD_EDIT_ACTIONS Add/Edit actions Aktionen einfügen / editieren
7 ADD_EDIT_ACTION Add/Edit action Aktion einfügen / editieren
8 ADD_ACTION Add action Aktion einfügen
9 REMOVE_ACTIONS Remove actions Aktionen entfernen
10 REMOVE_ACTION Remove action Aktion entfernen
11 MOUSE_MOVED_ACTIONS Mouse moved actions Mit der Maus bewegte Aktionen
12 ACTIONS_MOVED Actions moved Aktionen bewegt
13 CUT_SELECTION Cut selection Auswahl ausschneiden
14 REMOVE_SELECTION Remove selection Auswahl entfernen
15 PASTE_SELECTION Paste selection Auswahl einfügen
16 EQUALIZE Equalize Angleichen
17 INVERT Invert Invertieren
18 ISOLATE Isolate Isolieren
19 TOP_POINTS Top points Obere Punkte
20 MID_POINTS Mid points Mittlere Punkte
21 BOTTOM_POINTS Bottom points Untere Punkte
22 GENERATE_ACTIONS Generate actions Erzeuge Aktion
23 FRAME_ALIGN Frame align Frame angleichen
24 RANGE_EXTEND Range extend Reichweite erhöhen
25 REPEAT_STROKE Repeat stroke Wiederhole stroke
26 MOVE_TO_CURRENT_POSITION Move to current position Bewege zur aktuellen Position
27 SIMPLIFY Simplify Vereinfachen
28 LUA_SCRIPT Lua script Lua script
29 REDO_STACK Redo stack Stapel wiederherstellen
30 UNDO_STACK Undo stack Stapel rückgängig machen
31 UNDO_REDO_HISTORY Undo/Redo history Rückgängig/Wiederherstellen Verlauf
32 T_CODE T-Code T-Code
33 PORT Port Port
34 OPEN_PORT Open port Öffne Port
35 LIMITS Limits Limits
36 LINEAR_LIMITS Linear limits Lineare Limits
37 ROTATION_LIMITS Rotation limits Rotations Limits
38 VIBRATION_LIMITS Vibration limits Vibrations Limits
39 GLOBAL_SETTINGS Global settings Globale Einstellungen
40 DELAY Delay Verzögerung
41 CONTROLLER_BUTTON_A A / X A / X
42 CONTROLLER_BUTTON_B B / Circle B / Kreis
43 CONTROLLER_BUTTON_X X / Square X / Viereck
44 CONTROLLER_BUTTON_Y Y / Triangle Y / Dreieck
45 CONTROLLER_BUTTON_BACK Back / Share Zurück / Teilen
46 CONTROLLER_BUTTON_GUIDE Guide Anleitung
47 CONTROLLER_BUTTON_START Start Start
48 CONTROLLER_BUTTON_LEFTSTICK Leftstick Linker Stick
49 CONTROLLER_BUTTON_RIGHTSTICK Rightstick Rechter Stick
50 CONTROLLER_BUTTON_LEFTSHOULDER Leftshoulder Linke Schultertaste
51 CONTROLLER_BUTTON_RIGHTSHOULDER Rightshoulder Rechte Schultertaste
52 CONTROLLER_BUTTON_DPAD_UP DPAD Up DPAD oben
53 CONTROLLER_BUTTON_DPAD_DOWN DPAD Down DPAD unten
54 CONTROLLER_BUTTON_DPAD_LEFT DPAD Left DPAD links
55 CONTROLLER_BUTTON_DPAD_RIGHT DPAD Right DPAD rechts
56 CONTROLLER_NOT_SET - Not set - - Nicht gesetzt -
57 KEY_MOD_CTRL Ctrl Strg
58 KEY_MOD_ALT Alt Alt
59 KEY_MOD_SHIFT Shift Shift
60 KEY_ALREADY_IN_USE Key is in use Taste ist bereits in Benutzung
61 KEY_ALREADY_IN_USE_MSG Key already bound for [%s] Taste bereits belegt für [%s]
62 BUTTON_ALREADY_IN_USE Button is in use Taste ist bereits in Benutzung
63 BUTTON_ALREADY_IN_USE_MSG Button already bound for [%s] Taste bereits belegt für [%s]
64 DESCRIPTION Description Beschreibung
65 KEYBOARD Keyboard Tastatur
66 ACTIVE Active Aktiv
67 KEY_NOT_SET - Not set - - Nicht gesetzt -
68 CHANGE_KEY Change key Ändere Taste
69 CHANGE_KEY_MSG Press any key... Escape to clear. Drücke eine Taste... Escape zum Löschen.
70 PASSIVE_BINDING_TXT1 Here modifiers can be configured which change certain behaviour. Hier können Modifikatoren konfiguriert werden, die bestimmte Verhalten ändern.
71 PASSIVE_BINDING_TXT2 You can only use Shift, Ctrl & Alt. Du kannst nur Shift, Strg & Alt benutzen.
72 KEYS Keys Tasten
73 BINDINGS Bindings Tastenzuweisungen
74 BINDING_TXT1 You can use CTRL, SHIFT & ALT as modifiers. Du kannst STRG, SHIFT & ALT als Modifizierer benutzen.
75 BINDING_TXT2 Only controller buttons can be bound. The DPAD directions count as a buttons. Nur Controller Tasten können gesetzt werden. Die DPAD Richtungen fungieren als Tasten.
76 BINDING_TXT3 The configuration gets saved everytime a change is made. Änderungen werden gespeichert, sobald eine Änderung durchgeführt wird.
77 BINDING_TXT4 If you wan't to revert to the defaults, you'll have to delete the config. Wenn die zu den Standarteinstellungen zurückkehren möchtest, musst du die Config löschen.
78 FILTER Filter Filter
79 MODIFIERS Modifiers Modifizierer
80 ACTION Action Aktion
81 CONTROLLER Controller Controller
82 IGNORE_REPEATS Ignore repeats Ignoriere Wiederholungen
83 CHANGE_BUTTON Change button Ändere Taste
84 CHANGE_BUTTON_MSG Press any button... Escape to clear. Drücke eine Taste... Escape zum Löschen.
85 RUNNING_TASK Running task Laufender Prozess
86 THIS_MAY_TAKE_A_WHILE This may take a while... Das könnte eine Zeit dauern...
87 OPTIONS Options Optionen
88 AUTO_SCROLL Auto-scroll Auto-scroll
89 CLEAR Clear Beseitigen
90 COPY Copy Kopiere
91 USED Used Benutzt
92 ALLOCATED Allocated Zugewiesen
93 SCRIPTS Scripts Scripts
94 RENDERING Rendering Rendering
95 SHOW_ACTIONS Show actions Zeige Aktionen
96 SPLINE_MODE Spline mode Kurven-Modus
97 SHOW_VIDEO_POSITION Show video position Zeige Videopostition
98 WAVEFORM Waveform Waveform
99 SETTINGS Settings Einstellungen
100 SCALE Scale Skalierung
101 COLOR Color Farbe
102 ENABLE_WAVEFORM Enable waveform Aktiviere Waveform
103 MIN_INT_FMT Min: %d Min: %d
104 MAX_INT_FMT Max: %d Max: %d
105 TCODE_TICKRATE Tickrate (Hz) Tickrate (Hz)
106 SPLINE Spline Kurve
107 SPLINE_TOOLTIP Smooth motion instead of linear. Weiche Bewegung, statt linearer.
108 REMAP Remap Neu belegen
109 REMAP_TOOLTIP Remap script to use the full range. i.e. scripts using the range 10 to 90 become 0 to 100. Remap Script, damit es die volle Reichweite benutzt. Z.b. Scripts, die die Reichweite 10 bis 90 benutzen, werden zu 0 bis100.
110 DELAY_TOOLTIP Negative: Backward in time. Positive: Forward in time. Negativ: Zurück in der Zeit. Postiv: Vorwärts in der Zeit.
111 OUTPUTS Outputs Ausgaben
112 YOU_CAN_RIGHT_CLICK_SLIDERS_TOOLTIP You can right click sliders. Du kannst die Slider rechtsklicken.
113 REBALANCE Rebalance Rebalance
114 REBALANCE_TOOLTIP Balance around 500 even with unevenly spread limits. Balance um 500, selbst mit ungleichen Breite-Limits.
115 GAMEPAD_ONLY only nur
116 SHOW_VIDEO_POSITION_TOOLTIP (Frame overlay only) Shows a red line where the current frame is. More of a debugging feature. (Nur Frame Overlay) Zeigt eine Rote Linie, wo sich der aktuelle Frame befindet. Eher ein debugging Feature.
117 PROCESSING_AUDIO Processing audio... Verarbeite Audio...
118 UPDATE_WAVEFORM Update waveform Aktualisiere Waveform
119 POSITIONS Positions Positionen
120 LOOP_A_SET Loop A set Schleife bei A setzen (Loop-Modus)
121 LOOP_B_SET Loop B set Schleife bei B setzen (Loop-Modus)
122 LOCK Lock Sperren
123 CLICK_TO_ENABLE_VIDEO Click to enable video Drücke, um Video zu aktivieren.
124 LOOP_CLEARED Loop cleared Wiederholung gelöscht.
125 VIDEOPLAYER Player Player
126 SPEED Speed Geschwindigkeit
127 TIMELINE Timeline Zeitlinie
128 TIME Time Zeit
129 CONTROLS Controls Steuerung
130 TIMELINE_SECONDS seconds Sekunden
131 TASK_EXPORTING_CLIPS Exporting clips Exportiere Clips
132 PROJECT Project Projekt
133 MEDIA Media Medien
134 CHANGE_DEFAULT_LOCATION Change default location Ändere Standardverzeichnis
135 CHANGE_LOCATION Change location Ändere Verzeichnis
136 SCRIPTING_MODE Scripting mode Scripting Modus
137 DEFAULT_MODE Default Standard
138 ALTERNATING_MODE Alternating Abwechslend (Alternating)
139 DYNAMIC_INJECTION_MODE Dynamic injection Dynamische Injektion (Dynamic injection)
140 RECORDING_MODE Recording Aufnehmen
141 SCRIPTING_OVERLAY Scripting overlay Scripting overlay
142 FRAME_OVERLAY Frame Frame
143 TEMPO_OVERLAY Tempo Tempo
144 EMPTY_OVERLAY None nichts
145 OFFSET_MS Offset (ms) Versetzt (ms)
146 OFFSET_TOOLTIP Applies an offset to actions inserted while the video is playing. - : inserts earlier + : inserts later Wende eine Versetzung an, bei eingefügten Aktionen, während das Video spielt. - : füge früher ein + : füge später ein
147 MIRROR_MODE Mirror mode Spiegelmodus (Mirror Modus)
148 MIRROR_MODE_TOOLTIP Mirrors add/edit/remove action across all loaded scripts. Füge ein/editiere/entferne Spiegelungs-Aktionen (Mirros) bei allen geladenen Scripts.
149 DI_TARGET_SPEED Target speed (units/s) Ziel Geschwindigkeit (Einheiten/s)
150 DI_UP_DOWN_BIAS Up/Down speed bias Erhöhe/Verringe Geschwindigkeits-Bias
151 TOP Top Oben
152 BOTTOM Bottom Unten
153 NEXT_POINT Next point Nächster Punkt
154 NEXT_POINT_AT_FMT Next point is at %d Nächster Punkt ist bei %d
155 NEXT_POINT_IS_FMT Next point is %s Nächster Punkt ist %s
156 INVERTED inverted umgekehrt
157 NOT_INVERTED not inverted nicht umgekehrt
158 FIXED_RANGE Fixed range Fixierte Reichweite
159 CONTEXT_SENSITIVE Context sensitive Sensibler Inhalt
160 CONTEXT_SENSITIVE_TOOLTIP Alternates based on the previous action. Wechsel basierend auf der vorherigen Aktion.
161 MODE Mode Modus
162 MOUSE Mouse Maus
163 CONTROLLER_DEADZONE Controller deadzone Controller deadzone
164 DEADZONE Deadzone Deadzone
165 CENTER Center Mitte
166 TWO_AXES Two axes Zwei Axen
167 TWO_AXES_TOOLTIP Recording pitch & roll at once. Using Simulator 3D settings. Only works with a controller. Nehme pitch & roll gleichzeitig auf. Benutze 3D Simulator Einstellungen. Funktioniert nur mit einem Controller.
168 RECORD_ON_PLAY Record on play Aufnehmen beim Abspielen
169 TWO_AXES_AXES X / Y X / Y
170 POSITION Position Position
171 RECORDING_ACTIVE Recording active Aufnahme aktiv
172 RECORDING_PAUSED Recording paused Aufnahme pausiert
173 STATISTICS Statistics Statistiken
174 ACTION_EDITOR Action editor Aktionseditor
175 DYNAMIC_BINDING_GROUP Dynamic Dynamisch
176 ACTIONS_BINDING_GROUP Actions Aktionen
177 CORE_BINDING_GROUP Core Core
178 NAVIGATION_BINDING_GROUP Navigation Navigation
179 UTILITY_BINDING_GROUP Utility Utility
180 MOVING_BINDING_GROUP Moving Bewegen
181 SPECIAL_BINDING_GROUP Special Spezial
182 VIDEOPLAYER_BINDING_GROUP Video player Video player
183 EXTENSIONS_BINDING_GROUP Extensions Erweiterungen
184 CONTROLLER_BINDING_GROUP Controller Controller
185 ACTION_REMOVE_ACTION Remove action Entferne Aktion
186 ACTION_ACTION_0 Action at 0 Aktion bei 0
187 ACTION_ACTION_10 Action at 10 Aktion bei 10
188 ACTION_ACTION_20 Action at 20 Aktion bei 20
189 ACTION_ACTION_30 Action at 30 Aktion bei 30
190 ACTION_ACTION_40 Action at 40 Aktion bei 40
191 ACTION_ACTION_50 Action at 50 Aktion bei 50
192 ACTION_ACTION_60 Action at 60 Aktion bei 60
193 ACTION_ACTION_70 Action at 70 Aktion bei 70
194 ACTION_ACTION_80 Action at 80 Aktion bei 80
195 ACTION_ACTION_90 Action at 90 Aktion bei 90
196 ACTION_ACTION_100 Action at 100 Aktion bei 100
197 ACTION_SAVE_PROJECT Save project Speichere Projekt
198 ACTION_QUICK_EXPORT Quick export Schnelles exportieren
199 ACTION_SYNC_TIME_WITH_PLAYER Sync time with player Synchronisiere Zeit mit Player
200 ACTION_CYCLE_FORWARD_LOADED_SCRIPTS Cycle forward loaded scripts Schalte vorwärts zum gelandenen Script
201 ACTION_CYCLE_BACKWARD_LOADED_SCRIPTS Cycle backward loaded scripts Schalte zurück zum gelandenen Script
202 ACTION_PREVIOUS_ACTION Previous action Vorherige Aktion
203 ACTION_NEXT_ACTION Next action Nächste Aktion
204 ACTION_PREVIOUS_ACTION_MULTI Previous action (multi) Vorherige Aktion (multi)
205 ACTION_NEXT_ACTION_MULTI Next action (multi) Nächste Aktion (multi)
206 ACTION_PREV_FRAME Previous frame Vorheriger Frame
207 ACTION_NEXT_FRAME Next frame Nächster Frame
208 ACTION_FAST_STEP Fast step Schnelles Vorwärts
209 ACTION_FAST_BACKSTEP Fast backstep Schnelles Zurück
210 ACTION_UNDO Undo Rückgängig
211 ACTION_REDO Redo Wiederherstellen
212 ACTION_COPY Copy Kopieren
213 ACTION_PASTE Paste Einfügen
214 ACTION_CUT Cut Ausschneiden
215 ACTION_PASTE_EXACT Paste exact Füge exakt ein
216 ACTION_SELECT_ALL Select all Wähle alles aus
217 ACTION_DESELECT_ALL Deselect all Deselektiere alles
218 ACTION_SELECT_ALL_LEFT Select all left Wähle alles Linke aus
219 ACTION_SELECT_ALL_RIGHT Select all right Wähle alles Rechte aus
220 ACTION_SELECT_TOP Select top points Wähle Top Punke aus
221 ACTION_SELECT_BOTTOM Select bottom points Wähle Untere Punkte aus
222 ACTION_SELECT_MID Select middle points Wähle Mittlere Punkte aus
223 ACTION_TOGGLE_MIRROR_MODE Toggle mirror mode Schalte Spiegelmodus um
224 ACTION_SAVE_FRAME Save frame as image Speichere Frame als Bild
225 ACTION_CYCLE_SUBTITLES Cycle subtitles Wechsle Untertitel
226 ACTION_TOGGLE_FULLSCREEN Toggle fullscreen Schalte Vollbild um
227 ACTION_MOVE_UP_10 Move actions +10 up Bewege Aktion +10 nach oben
228 ACTION_MOVE_DOWN_10 Move actions -10 down Bewege Aktion - 10 nach unten
229 ACTION_MOVE_UP_5 Move actions +5 up Bewege Aktion + 5 nach oben
230 ACTION_MOVE_DOWN_5 Move actions -5 down Bewege Aktion - 5 nach unten
231 ACTION_MOVE_ACTIONS_LEFT_SNAP Move actions left with snapping Bewege Aktion nach links mit snapping
232 ACTION_MOVE_ACTIONS_RIGHT_SNAP Move actions right with snapping Bewege Aktionen nach rechts mit snapping
233 ACTION_MOVE_ACTIONS_LEFT Move actions left Bewege Aktionen nach links
234 ACTION_MOVE_ACTIONS_RIGHT Move actions right Bewege Aktionen nach rechts
235 ACTION_MOVE_ACTIONS_UP Move actions up Bewege Aktionen nach oben
236 ACTION_MOVE_ACTIONS_DOWN Move actions down Bewege Aktionen nach unten
237 ACTION_MOVE_TO_CURRENT_POSITION Move to current position Bewege zur aktuellen Position
238 ACTION_EQUALIZE_ACTIONS Equalize actions Gleiche Aktionen an
239 ACTION_INVERT_ACTIONS Invert actions Kehre Aktionen um
240 ACTION_ISOLATE_ACTION Isolate action Isoliere Aktionen
241 ACTION_REPEAT_STROKE Repeat stroke Wiederhole Stroke
242 ACTION_TOGGLE_PLAY Play / Pause Abspielen / Pause
243 ACTION_REDUCE_PLAYBACK_SPEED Playback speed -10% Abspielgeschwindigkeit -10%
244 ACTION_INCREASE_PLAYBACK_SPEED Playback speed +10% Abspielgeschwindigkeit +10%
245 ACTION_GO_TO_START Go to the start Gehe zu Start
246 ACTION_GO_TO_END Go to the end Gehe zu Ende
247 ACTION_RELOAD_ENABLED_EXTENSIONS Reload enabled extensions Lade aktivierte Erweiterungen
248 ACTION_TOGGLE_CONTROLLER_NAV Toggle controller navigation Schalte Controller Navigation um
249 ACTION_SEEK_FORWARD_1 Forward 1 second 1 Sekunde vorwärts
250 ACTION_SEEK_BACKWARD_1 Backward 1 second 1 Sekunden zurück
251 ACTION_ADD_ACTION_CONTROLLER Add action Füge Aktion ein
252 ACTION_TOGGLE_RECORDING_MODE Toggle recording mode Schalte Aufnahmemodus um
253 ACTION_CONTROLLER_SELECT Controller selection Controller Auswahl
254 ACTION_SET_PLAYBACK_SPEED Set current playback speed Setze aktuelle Wiedergabegeschwindigkeit
255 PASSIVE_GROUP_TIMELINE Point timeline Script Zeitlinie
256 PASSIVE_GROUP_SIMULATOR Simulator Simulator
257 MOD_MOVE_OR_ADD_POINT Click drag/add point in the timeline Klicke und ziehe/füge Punkt in Zeitlinie ein
258 MOD_CLICK_SIM_ADD_PONT Click simulator to add a point Klicke Simulator, um Punkt einzufügen
259 PROJECT_HAS_UNSAVED_EDITS Project has unsaved edits Projekt hat nicht gespeicherte Änderungen
260 UNSAVED_EDITS_MSG The current project has unsaved edits. Das aktuelle Projekt hat nicht gespeicherte Änderungen.
261 UNSAVED_CHANGES Unsaved changes Nicht gespeicherte Änderungen
262 UNSAVED_CHANGES_MSG Do you want to save and exit? Möchtest du speichern und beenden?
263 FILE_NOT_FOUND File not found Datei nicht gefunden
264 COULDNT_FIND_FILE Couldn’t find file Konnte Datei nicht finden
265 OFS_FAILED_TO_IMPORT OpenFunscripter failed to import. OpenFunscripter konnte nicht importieren.
266 OFS_FAILED_TO_IMPORT_MSG Failed to import Importieren fehlgeschlagen
267 FAILED_TO_LOAD Failed to load Laden fehlgeschlagen
268 FAILED_TO_LOAD_MSG The project failed to load. Das Projekt konnte nicht geladen werden.
269 FAILED_TO_FIND_VIDEO Failed to find video Konnte Video nicht finden
270 FAILED_TO_FIND_VIDEO_MSG The video was not found. Please pick the correct video. Das Video wurde nicht gefunden. Wähle bitte das richtige Video aus.
271 CHOOSE_OUTPUT_DIR Choose output directory Wähle Ausgansverzeichnis
272 PICK_DIFFERENT_MEDIA Pick different media Wähle anderes Medium
273 FILE File Datei
274 OPEN_PROJECT Open project Öffne Projekt
275 SAVE Save Speichern
276 CLOSE_PROJECT Close project Schließe Projekt
277 WRONG_FILE Wrong file Falsche Datei
278 WRONG_FILE_MSG The file isn’t a project file. Diese Datei ist keine Projekt-Datei
279 IMPORT_VIDEO_SCRIPT Import video/script Video/Script importieren
280 RECENT_FILES Recent files Kürzliche Datein
281 NO_RECENT_FILES No recent files Keine kürzliche Datein
282 SAVE_PROJECT Save project Speichere Projekt
283 EXPORT_MENU Export... Exportiere...
284 QUICK_EXPORT Quick export Schnelles Exportieren
285 QUICK_EXPORT_TOOLTIP Exports all scripts as .funscript in their default paths. Exportiere alle Scripts als.funscript in ihren Standardpfaden.
286 EXPORT_ACTIVE_SCRIPT Export active script Exportiere aktives Script.
287 EXPORT_ALL Export all Exportiere alles
288 AUTO_BACKUP_TIMER_FMT Auto Backup in %d seconds Auto Backup in %d Sekunden
289 AUTO_BACKUP Auto Backup Auto Backup
290 OPEN_BACKUP_DIR Open backup directory Öffne Backupordner
291 CONFIGURE Configure Konfiguriere
292 ADD_MENU Add... Füge hinzu...
293 ADD_SHORTCUTS Shortcuts Tastenkürzel
294 ADD_NEW Add new Füge neu ein
295 ADD_NEW_FUNSCRIPT Add new funscript Füges neues funscript ein
296 ADD_EXISTING Add existing Füge bestehendes ein
297 ADD_EXISTING_FUNSCRIPTS Add existing funscripts Füge bestehendes funscript ein
298 REMOVE_SCRIPT_CONFIRM_MSG If the script wasn’t previously exported, this can’t be reverted. Continue? Falls das Script zuvor nicht exportiert wurde, kann dies nicht rückgängig gemacht werden. Fortsetzen?
299 REMOVE Remove Entferne
300 REMOVE_SCRIPT Remove script Entferne Script
301 EDIT Edit Editiere
302 SAVE_FRAME_AS_IMAGE Save frame as image Speichere Frame als Bild
303 OPEN_SCREENSHOT_DIR Open screenshot directory Öffne Screenshotordner
304 SAVE_HEATMAP Save heatmap Speichere heatmap
305 UNDO Undo Rückgängig
306 REDO Redo Wiederholen
307 CUT Cut Aussschneiden
308 PASTE Paste Einfügen
309 SELECT Select Auswählen
310 SELECT_ALL Select all Wähle alles aus
311 DESELECT_ALL Deselect all Wähle alles ab
312 SPECIAL Special Speziall
313 SELECT_ALL_LEFT Select all left Wähle alles Linke aus
314 SELECT_ALL_RIGHT Select all right Wähle alles Rechte aus
315 SET_SELECTION_START Set selection start Wähle Auswahl Anfang
316 SET_SELECTION_END Set selection end Wähle Auswahl Ende
317 TOP_POINTS_ONLY Top points only Nur obere Punke
318 MID_POINTS_ONLY Mid points only Nur mittlere Punkte
319 BOTTOM_POINTS_ONLY Bottom points only Nur untere Punkte
320 BOOKMARKS Bookmarks Lesezeichen
321 EXPORT_CLIPS Export clips Exportiere Clips
322 EXPORT_CLIPS_TOOLTIP Export smaller clips based on bookmarks. Exportiere kürzere Clips, basierend auf Lesezeichen.
323 NAME Name Name
324 ADD_BOOKMARK Add bookmark Füge Lesezeichen ein
325 CREATE_INTERVAL_FOR_FMT Create interval for "%s" Erstelle Intervall für "%s"
326 GO_TO_MENU Go to... Gehe zu...
327 NO_BOOKMARKS No bookmarks Keine Lesezeichen
328 ALWAYS_SHOW_LABELS Always show labels Zeige immer Bezeichnung
329 DELETE_ALL_BOOKMARKS Delete all bookmarks Lösche alle Lesezeichen
330 VIEW_MENU View Zeige
331 SIMULATOR_3D Simulator 3D 3D Simulator
332 METADATA Metadata Metadata
333 DRAW_VIDEO Draw video Zeige Video
334 RESET_VIDEO_POS Reset video position Setze Videoposition zurück
335 VIDEO_MODE Video mode Videomodus
336 VIDEO_MODE_FULL Full Voll
337 VIDEO_MODE_LEFT_PANE Left pane Linke Seite
338 VIDEO_MODE_RIGHT_PANE Right pane Rechte Seite
339 VIDEO_MODE_TOP_PANE Top pane Obere Seite
340 VIDEO_MODE_BOTTOM_PANE Bottom pane Untere Seite
341 VIDEO_MODE_VR VR VR
342 DEBUG Debug Debug
343 METRICS Metrics Metrik
344 LOG_OUTPUT Log output Log Output
345 FULLSCREEN Fullscreen Vollbild
346 PREFERENCES Preferences Einstellungen
347 REPEAT_RATE Repeat rate Wiederholungsrate
348 CONTROLLER_CONNECTED Controller connected! Controller verbunden!
349 EXTENSIONS_MENU Extensions Erweiterungen
350 DEV_MODE Developer mode Entwicklermodus
351 SHOW_LOGS Show logs Zeige Logs
352 DEV_MODE_TOOLTIP Enable extra functionality for extension developement. Erlaube extra Funktionen für Erweiterungsentwicklung
353 EXTENSION_DIR Extension directory Erweiterungsverzeichnis
354 ENABLED Enabled Aktiviert
355 SHOW_WINDOW Show window Zeige Fenster
356 OPEN_DIRECTORY Open directory Öffne Verzeichnis
357 NAVIGATION Navigation Navigation
358 SCRIPTING Scripting Scripting
359 UNSAVED_CHANGES_FMT unsaved changes %d minutes ago Ungespeichterte Änderungen seit %d Minuten
360 METADATA_EDITOR Metadate editor Metadata Editor
361 TITLE Title Titel
362 DURATION Duration Dauer
363 CREATOR Creator Ersteller
364 URL Url Url
365 VIDEO_URL Video url Video url
366 NOTES Notes Notizen
367 LICENSE License Linzenz
368 FREE Free Kostenlos
369 PAID Paid Kostenpflichtig
370 NONE None Keine
371 TAGS Tags Schlagwörter
372 ADD Add Füge ein
373 PERFORMERS Performers Darsteller
374 SAVE_TEMPLATE Save template Speichere Vorlage
375 SAVE_TEMPLATE_TOOLTIP Saves all current values as defaults for later. Speichere alle aktuellen Werte als Standard für später.
376 GIT_COMMIT Commit Commit
377 INTERVAL Interval Intervall
378 CLOSE_WITHOUT_SAVING Close without saving? Schließen ohne zu speichern?
379 CLOSE_WITHOUT_SAVING_MSG The current project has unsaved changes do you want to close it without saving? Das aktuelle Projekt hat ungespeicherte Änderungen. Willst du es ohne zu speichern schließen?
380 CONFIGURATION Configuration Konfiguration
381 RESET Reset Zurücksetzen
382 MOVE Move Bewege
383 DISTANCE Distance Distanz
384 GLOBAL_YAW Global yaw Globales yaw
385 GLOBAL_PITCH Global pitch Globales pitch
386 BOX Box Box
387 CONTAINER Container Container
388 TWIST Twist Twist
389 ROLL_DEG Roll deg Roll Grad
390 PITCH_DEG Pitch deg Pitch Grad
391 TWIST_DEG Twist deg Twist Grad
392 ROLL Roll Roll
393 PITCH Pitch Pitch
394 YAW Yaw Yaw
395 INSERT_CURRENT_POSITION Insert current position Füge aktuelle Position ein
396 SCROLL_PERCENT Scroll (%) Scroll (%)
397 SCROLL_PERCENT_TOOLTIP You can use the mousewheel on the sliders above. Du kannst das Mausrad für die oberen Regler benutzen.
398 EXTENSION_LOG_OUTPUT Extension log output Erweiterungen log output
399 ERROR_STR Error Fehler
400 TRY_RELOADING Try reloading Versuche neu laden
401 RELOAD Reload Lade neu
402 BPM BPM BPM
403 OFFSET Offset Versetzung (Offset)
404 SNAP Snap Snap
405 UNKNOWN_ERROR unknown error Unbekannter Fehler
406 FFMPEG_WAS_NOT_FOUND_MSG ffmpeg.exe was not found. Do you want to download it? ffmpeg.exe wurde nicht gefunden. Möchtest du es herunterladen?
407 BINDABLE_FUNCTIONS Bindable functions Funktionen, die als Tastenkürzel gesetzt werden können
408 YES Yes Ja
409 FFMPEG_FAILED_TO_DOWNLOAD_MSG Failed to download from https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip Fehler beim Herunterladen von https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip
410 DONE Done Fertig
411 DONE_MSG ffmpeg.exe was successfully extracted. ffmpeg.exe wurde erfolgreiche extrahiert.
412 EXTRACT_FAIL Failed to extract ffmpeg.exe. Fehler beim Extrahieren von fffmpeg.exe.
413 EXTRACT_FAIL_MSG Extracting uses tar.exe. It will fail if it's not on your system. Extrahieren benutzt tar.exe. Es wird nicht funktionieren, wenn es nicht installiert ist.
414 DOWNLOAD_FFMPEG Download ffmpeg? Download ffmpeg?
415 TEMPO_WHOLE_MEASURES whole measures Ganze Maße
416 TEMPO_2ND_MEASURES 2nd measures 2te Maße
417 TEMPO_4TH_MEASURES 4th measures 4te Maße
418 TEMPO_8TH_MEASURES 8th measures 8te Maße
419 TEMPO_12TH_MEASURES 12th measures 12te Maße
420 TEMPO_16TH_MEASURES 16th measures 16te Maße
421 TEMPO_24TH_MEASURES 24th measures 24ste Maße
422 TEMPO_32ND_MEASURES 32nd measures 32ste Maße
423 TEMPO_48TH_MEASURES 48th measures 48ste Maße
424 TEMPO_64TH_MEASURES 64th measures 64ste Maße
425 LOAD_CONFIG Load config Lade Config
426 SAVE_CONFIG Save config Speichere Config
427 SAVE_SIMULATOR_CONFIG Save simulator configuration Speichere Simulator Konfiguration
428 SAVE_SIMULATOR_CONFIG_MSG Do you want do save the current config? This will override any existing default config. Möchstest du die aktuelle Config speichern? Dies wird sämtliche existierenden Standard Configs überschreiben.
429 LINES Lines Linien
430 TEXT Text Text
431 FRONT Front Vorne
432 BACK Back Hinten
433 BORDER Border Rahmen
434 INDICATOR Indicator Indikator
435 LINE Line Linie
436 WIDTH Width Weite
437 OPACITY Opacity Deckkraft
438 EXTRA_LINES Extra lines Extra Linien
439 VANILLA Vanilla Vanilla
440 SHOW_POSITION Show position Zeige Position
441 VANILLA_TOOLTIP The original simulator from day one. Der originale Simulator von der ersten Version.
442 RESET_TO_DEFAULTS Reset to defaults Setze zu Standard zurück
443 SIMULATOR Simulator Simulator
444 APPLICATION Application Applikation
445 DARK_MODE Dark mode Dunkler Modus
446 LIGHT_MODE Light mode Heller Modus
447 PREFERENCES_TXT Higher frame rate makes OFS feel "snappier" because input gets processed more frequently. Höhere Frameraten lassen OFS "snappier" anfühlen, weil Eingaben häufiger verarbeitet werden.
448 VSYNC Vsync Vsync
449 VSYNC_TOOLTIP Limits frame rate to the refresh rate of the monitor. Frame limit is ignored. Limitiert Frame Rate auf die Wiederholungsrate des Monitors. Frame Limitierung wird ignoriert.
450 FRAME_LIMIT Frame limit Frame Limitierung
451 FRAME_LIMIT_TOOLTIP This limits the frame rate OFS is running at. Das limitiert die Frame Rate, in welcher OFS läuft.
452 FONT Font Schrift
453 CHANGE Change Ändere
454 CHOOSE_FONT Choose font Wähle Schrift
455 DEFAULT_FONT Default font Standardschrift
456 FONT_SIZE Font size Schriftgröße
457 FORCE_HW_DECODING Force hardware decoding (Requires program restart) Erzwinge Hardwarebeschleunigung (Erfordert Neustart)
458 FORCE_HW_DECODING_TOOLTIP May cause crashes on some systems. Kann bei einigen System abstürzen.
459 FAST_FRAME_STEP Fast frame step Schneller Frame Step
460 FAST_FRAME_STEP_TOOLTIP Amount of frames to skip with fast step. Wieviel Frames beim schnellen Frame Step geskipt werden.
461 SHOW_METADATA_DIALOG_ON_NEW_PROJECT Show metadata dialog on new project Zeige Metadata Fenster bei einem neuen Projekt.
462 FUNCTIONS_RANGE_EXTENDER Range extender Reichweitenverlängerer
463 FUNCTIONS_SIMPLIFY Simplify (Ramer-Douglas-Peucker) Vereinfache (Ramer-Douglas-Peucker)
464 RANGE Range Reichweite
465 RANGE_EXTENDER_TXT Select atleast 5 actions to extend. Wähle mindestens 5 Aktionen zum Verlängern.
466 EPSILON Epsilon Epsilon
467 SIMPLIFY_TXT Select atleast 5 actions to simplify. Wähle mindestens 5 Aktionen zum Vereinfachen.
468 SPECIAL_FUNCTIONS Special functions Spezielle Funktionen
469 MEMORY_USAGE Memory usage Speichergebrauch
470 UPDATE Update Update
471 SLOWEST slowest langsamste
472 LANGUAGE Language Sprache

504
de_zh.csv Normal file
View File

@ -0,0 +1,504 @@
Key (do not touch),Default,Translation
INVALID_TR,%%this should not be displayed%%,%%this should not be displayed%%
ABOUT,About,关于
LATEST_RELEASE,Latest release,最新版本
OFS_LOG_OUTPUT,OFS Log Output,OFS 日志输出
ADD_EDIT_ACTIONS,Add/Edit actions,添加/编辑动作
ADD_EDIT_ACTION,Add/Edit action,添加/编辑动作
ADD_ACTION,Add action,添加动作
REMOVE_ACTIONS,Remove actions,移除动作
REMOVE_ACTION,Remove action,移除动作
MOUSE_MOVED_ACTIONS,Mouse moved actions,鼠标移动动作
ACTIONS_MOVED,Actions moved,动作已移动
CUT_SELECTION,Cut selection,剪切选择
REMOVE_SELECTION,Remove selection,移除选择
PASTE_SELECTION,Paste selection,粘贴选择
EQUALIZE,Equalize,均衡
INVERT,Invert,反转
ISOLATE,Isolate,隔离
TOP_POINTS,Top points,顶部点
MID_POINTS,Mid points,中间点
BOTTOM_POINTS,Bottom points,底部点
GENERATE_ACTIONS,Generate actions,生成动作
FRAME_ALIGN,Frame align,帧对齐
RANGE_EXTEND,Range extend,范围扩展
REPEAT_STROKE,Repeat stroke,重复笔画
MOVE_TO_CURRENT_POSITION,Move to current position,移动到当前位置
SIMPLIFY,Simplify,简化
LUA_SCRIPT,Lua script,Lua 脚本
REDO_STACK,Redo stack,重做栈
UNDO_STACK,Undo stack,撤销栈
UNDO_REDO_HISTORY,Undo/Redo history,撤销/重做历史
T_CODE,T-Code,T-Code
PORT,Port,端口
OPEN_PORT,Open port,打开端口
LIMITS,Limits,限制
LINEAR_LIMITS,Linear limits,线性限制
ROTATION_LIMITS,Rotation limits,旋转限制
VIBRATION_LIMITS,Vibration limits,振动限制
GLOBAL_SETTINGS,Global settings,全局设置
DELAY,Delay,延迟
CONTROLLER_BUTTON_A,A / X,A / X
CONTROLLER_BUTTON_B,B / Circle,B / 圆圈
CONTROLLER_BUTTON_X,X / Square,X / 方块
CONTROLLER_BUTTON_Y,Y / Triangle,Y / 三角
CONTROLLER_BUTTON_BACK,Back / Share,返回 / 分享
CONTROLLER_BUTTON_GUIDE,Guide,指南
CONTROLLER_BUTTON_START,Start,开始
CONTROLLER_BUTTON_LEFTSTICK,Leftstick,左摇杆
CONTROLLER_BUTTON_RIGHTSTICK,Rightstick,右摇杆
CONTROLLER_BUTTON_LEFTSHOULDER,Leftshoulder,左肩键
CONTROLLER_BUTTON_RIGHTSHOULDER,Rightshoulder,右肩键
CONTROLLER_BUTTON_DPAD_UP,DPAD Up,方向键上
CONTROLLER_BUTTON_DPAD_DOWN,DPAD Down,方向键下
CONTROLLER_BUTTON_DPAD_LEFT,DPAD Left,方向键左
CONTROLLER_BUTTON_DPAD_RIGHT,DPAD Right,方向键右
CONTROLLER_NOT_SET,- Not set -,- 未设置 -
KEY_MOD_CTRL,Ctrl,Ctrl
KEY_MOD_ALT,Alt,Alt
KEY_MOD_SHIFT,Shift,Shift
KEY_ALREADY_IN_USE,Key is in use,按键已被使用
KEY_ALREADY_IN_USE_MSG,Key already bound for [%s],按键已绑定到 [%s]
BUTTON_ALREADY_IN_USE,Button is in use,按钮已被使用
BUTTON_ALREADY_IN_USE_MSG,Button already bound for [%s],按钮已绑定到 [%s]
DESCRIPTION,Description,描述
KEYBOARD,Keyboard,键盘
ACTIVE,Active,激活
KEY_NOT_SET,- Not set -,- 未设置 -
CHANGE_KEY,Change key,更改按键
CHANGE_KEY_MSG,"Press any key...
Escape to clear.","按任意键...
Escape 清除。"
PASSIVE_BINDING_TXT1,Here modifiers can be configured which change certain behaviour.,"这里可以配置修饰键来改变某些行为。"
PASSIVE_BINDING_TXT2,"You can only use Shift, Ctrl & Alt.","你只能使用 Shift、Ctrl 和 Alt。"
KEYS,Keys,按键
BINDINGS,Bindings,按键绑定
BINDING_TXT1,"You can use CTRL, SHIFT & ALT as modifiers.","你可以使用 CTRL、SHIFT 和 ALT 作为修饰键。"
BINDING_TXT2,Only controller buttons can be bound. The DPAD directions count as a buttons.,只能绑定控制器按钮。方向键也算作按钮。
BINDING_TXT3,The configuration gets saved everytime a change is made.,"每次更改都会保存配置。"
BINDING_TXT4,"If you wan't to revert to the defaults, you'll have to delete the config.","如果你想恢复默认设置,需要删除配置文件。"
FILTER,Filter,过滤器
MODIFIERS,Modifiers,修饰键
ACTION,Action,动作
CONTROLLER,Controller,控制器
IGNORE_REPEATS,Ignore repeats,忽略重复
CHANGE_BUTTON,Change button,更改按钮
CHANGE_BUTTON_MSG,"Press any button...
Escape to clear.","按任意按钮...
Escape 清除。"
RUNNING_TASK,Running task,运行任务
THIS_MAY_TAKE_A_WHILE,This may take a while...,这可能需要一段时间...
OPTIONS,Options,选项
AUTO_SCROLL,Auto-scroll,自动滚动
CLEAR,Clear,清除
COPY,Copy,复制
USED,Used,已使用
ALLOCATED,Allocated,已分配
SCRIPTS,Scripts,脚本
RENDERING,Rendering,渲染
SHOW_ACTIONS,Show actions,显示动作
SPLINE_MODE,Spline mode,样条模式
SHOW_VIDEO_POSITION,Show video position,显示视频位置
WAVEFORM,Waveform,波形
SETTINGS,Settings,设置
SCALE,Scale,缩放
COLOR,Color,颜色
ENABLE_WAVEFORM,Enable waveform,启用波形
MIN_INT_FMT,Min: %d,最小值: %d
MAX_INT_FMT,Max: %d,最大值: %d
TCODE_TICKRATE,Tickrate (Hz),频率 (Hz)
SPLINE,Spline,样条
SPLINE_TOOLTIP,Smooth motion instead of linear.,"平滑运动而不是线性运动。"
REMAP,Remap,重新映射
REMAP_TOOLTIP,"Remap script to use the full range.
i.e. scripts using the range 10 to 90 become 0 to 100.","重新映射脚本以使用完整范围。
使用10-90范围的脚本变为0-100。"
DELAY_TOOLTIP,"Negative: Backward in time.
Positive: Forward in time.","负值:时间向后。
正值:时间向前。"
OUTPUTS,Outputs,输出
YOU_CAN_RIGHT_CLICK_SLIDERS_TOOLTIP,You can right click sliders.,你可以右键点击滑块。
REBALANCE,Rebalance,重新平衡
REBALANCE_TOOLTIP,Balance around 500 even with unevenly spread limits.,"即使限制分布不均也要围绕500平衡。"
GAMEPAD_ONLY,only,仅
SHOW_VIDEO_POSITION_TOOLTIP,"(Frame overlay only)
Shows a red line where the current frame is.
More of a debugging feature.","(仅帧叠加)
在当前帧位置显示红线。
更多的是调试功能。"
PROCESSING_AUDIO,Processing audio...,处理音频中...
UPDATE_WAVEFORM,Update waveform,更新波形
POSITIONS,Positions,位置
LOOP_A_SET,Loop A set,循环A设置
LOOP_B_SET,Loop B set,循环B设置
LOCK,Lock,锁定
CLICK_TO_ENABLE_VIDEO,Click to enable video,"点击启用视频。"
LOOP_CLEARED,Loop cleared,循环已清除
VIDEOPLAYER,Player,播放器
SPEED,Speed,速度
TIMELINE,Timeline,时间轴
TIME,Time,时间
CONTROLS,Controls,控制
TIMELINE_SECONDS,seconds,秒
TASK_EXPORTING_CLIPS,Exporting clips,导出片段
PROJECT,Project,项目
MEDIA,Media,媒体
CHANGE_DEFAULT_LOCATION,Change default location,更改默认位置
CHANGE_LOCATION,Change location,更改位置
SCRIPTING_MODE,Scripting mode,脚本模式
DEFAULT_MODE,Default,默认
ALTERNATING_MODE,Alternating,交替
DYNAMIC_INJECTION_MODE,Dynamic injection,动态注入
RECORDING_MODE,Recording,录制
SCRIPTING_OVERLAY,Scripting overlay,脚本叠加
FRAME_OVERLAY,Frame,帧
TEMPO_OVERLAY,Tempo,节拍
EMPTY_OVERLAY,None,无
OFFSET_MS,Offset (ms),偏移 (毫秒)
OFFSET_TOOLTIP,"Applies an offset to actions inserted while the video is playing.
- : inserts earlier
+ : inserts later","对视频播放时插入的动作应用偏移。
- : 提前插入
+ : 延后插入"
MIRROR_MODE,Mirror mode,镜像模式
MIRROR_MODE_TOOLTIP,Mirrors add/edit/remove action across all loaded scripts.,在所有加载的脚本中镜像添加/编辑/删除动作。
DI_TARGET_SPEED,Target speed (units/s),目标速度 (单位/秒)
DI_UP_DOWN_BIAS,Up/Down speed bias,上/下速度偏差
TOP,Top,顶部
BOTTOM,Bottom,底部
NEXT_POINT,Next point,下一个点
NEXT_POINT_AT_FMT,Next point is at %d,下一个点在 %d
NEXT_POINT_IS_FMT,Next point is %s,下一个点是 %s
INVERTED,inverted,反转的
NOT_INVERTED,not inverted,未反转的
FIXED_RANGE,Fixed range,固定范围
CONTEXT_SENSITIVE,Context sensitive,上下文敏感
CONTEXT_SENSITIVE_TOOLTIP,Alternates based on the previous action.,基于前一个动作交替。
MODE,Mode,模式
MOUSE,Mouse,鼠标
CONTROLLER_DEADZONE,Controller deadzone,控制器死区
DEADZONE,Deadzone,死区
CENTER,Center,中心
TWO_AXES,Two axes,双轴
TWO_AXES_TOOLTIP,"Recording pitch & roll at once.
Using Simulator 3D settings.
Only works with a controller.","同时记录俯仰和翻滚。
使用3D模拟器设置。
仅适用于控制器。"
RECORD_ON_PLAY,Record on play,播放时录制
TWO_AXES_AXES,X / Y,X / Y
POSITION,Position,位置
RECORDING_ACTIVE,Recording active,录制激活
RECORDING_PAUSED,Recording paused,录制暂停
STATISTICS,Statistics,统计
ACTION_EDITOR,Action editor,动作编辑器
DYNAMIC_BINDING_GROUP,Dynamic,动态
ACTIONS_BINDING_GROUP,Actions,动作
CORE_BINDING_GROUP,Core,核心
NAVIGATION_BINDING_GROUP,Navigation,导航
UTILITY_BINDING_GROUP,Utility,实用工具
MOVING_BINDING_GROUP,Moving,移动
SPECIAL_BINDING_GROUP,Special,特殊
VIDEOPLAYER_BINDING_GROUP,Video player,视频播放器
EXTENSIONS_BINDING_GROUP,Extensions,扩展
CONTROLLER_BINDING_GROUP,Controller,控制器
ACTION_REMOVE_ACTION,Remove action,移除动作
ACTION_ACTION_0,Action at 0,在0处的动作
ACTION_ACTION_10,Action at 10,在10处的动作
ACTION_ACTION_20,Action at 20,在20处的动作
ACTION_ACTION_30,Action at 30,在30处的动作
ACTION_ACTION_40,Action at 40,在40处的动作
ACTION_ACTION_50,Action at 50,在50处的动作
ACTION_ACTION_60,Action at 60,在60处的动作
ACTION_ACTION_70,Action at 70,在70处的动作
ACTION_ACTION_80,Action at 80,在80处的动作
ACTION_ACTION_90,Action at 90,在90处的动作
ACTION_ACTION_100,Action at 100,在100处的动作
ACTION_SAVE_PROJECT,Save project,保存项目
ACTION_QUICK_EXPORT,Quick export,快速导出
ACTION_SYNC_TIME_WITH_PLAYER,Sync time with player,与播放器同步时间
ACTION_CYCLE_FORWARD_LOADED_SCRIPTS,Cycle forward loaded scripts,向前循环已加载的脚本
ACTION_CYCLE_BACKWARD_LOADED_SCRIPTS,Cycle backward loaded scripts,向后循环已加载的脚本
ACTION_PREVIOUS_ACTION,Previous action,上一个动作
ACTION_NEXT_ACTION,Next action,下一个动作
ACTION_PREVIOUS_ACTION_MULTI,Previous action (multi),上一个动作(多选)
ACTION_NEXT_ACTION_MULTI,Next action (multi),下一个动作(多选)
ACTION_PREV_FRAME,Previous frame,上一帧
ACTION_NEXT_FRAME,Next frame,下一帧
ACTION_FAST_STEP,Fast step,快速步进
ACTION_FAST_BACKSTEP,Fast backstep,快速回退
ACTION_UNDO,Undo,撤销
ACTION_REDO,Redo,重做
ACTION_COPY,Copy,复制
ACTION_PASTE,Paste,粘贴
ACTION_CUT,Cut,剪切
ACTION_PASTE_EXACT,Paste exact,精确粘贴
ACTION_SELECT_ALL,Select all,全选
ACTION_DESELECT_ALL,Deselect all,取消全选
ACTION_SELECT_ALL_LEFT,Select all left,选择左侧全部
ACTION_SELECT_ALL_RIGHT,Select all right,选择右侧全部
ACTION_SELECT_TOP,Select top points,选择顶部点
ACTION_SELECT_BOTTOM,Select bottom points,选择底部点
ACTION_SELECT_MID,Select middle points,选择中间点
ACTION_TOGGLE_MIRROR_MODE,Toggle mirror mode,切换镜像模式
ACTION_SAVE_FRAME,Save frame as image,保存帧为图像
ACTION_CYCLE_SUBTITLES,Cycle subtitles,循环字幕
ACTION_TOGGLE_FULLSCREEN,Toggle fullscreen,切换全屏
ACTION_MOVE_UP_10,Move actions +10 up,向上移动动作+10
ACTION_MOVE_DOWN_10,Move actions -10 down,向下移动动作-10
ACTION_MOVE_UP_5,Move actions +5 up,向上移动动作+5
ACTION_MOVE_DOWN_5,Move actions -5 down,向下移动动作-5
ACTION_MOVE_ACTIONS_LEFT_SNAP,Move actions left with snapping,向左移动动作(带对齐)
ACTION_MOVE_ACTIONS_RIGHT_SNAP,Move actions right with snapping,向右移动动作(带对齐)
ACTION_MOVE_ACTIONS_LEFT,Move actions left,向左移动动作
ACTION_MOVE_ACTIONS_RIGHT,Move actions right,向右移动动作
ACTION_MOVE_ACTIONS_UP,Move actions up,向上移动动作
ACTION_MOVE_ACTIONS_DOWN,Move actions down,向下移动动作
ACTION_MOVE_TO_CURRENT_POSITION,Move to current position,移动到当前位置
ACTION_EQUALIZE_ACTIONS,Equalize actions,均衡动作
ACTION_INVERT_ACTIONS,Invert actions,反转动作
ACTION_ISOLATE_ACTION,Isolate action,隔离动作
ACTION_REPEAT_STROKE,Repeat stroke,重复笔画
ACTION_TOGGLE_PLAY,Play / Pause,播放/暂停
ACTION_REDUCE_PLAYBACK_SPEED,Playback speed -10%,播放速度-10%
ACTION_INCREASE_PLAYBACK_SPEED,Playback speed +10%,播放速度+10%
ACTION_GO_TO_START,Go to the start,转到开始
ACTION_GO_TO_END,Go to the end,转到结束
ACTION_RELOAD_ENABLED_EXTENSIONS,Reload enabled extensions,重新加载已启用的扩展
ACTION_TOGGLE_CONTROLLER_NAV,Toggle controller navigation,切换控制器导航
ACTION_SEEK_FORWARD_1,Forward 1 second,前进1秒
ACTION_SEEK_BACKWARD_1,Backward 1 second,后退1秒
ACTION_ADD_ACTION_CONTROLLER,Add action,添加动作
ACTION_TOGGLE_RECORDING_MODE,Toggle recording mode,切换录制模式
ACTION_CONTROLLER_SELECT,Controller selection,控制器选择
ACTION_SET_PLAYBACK_SPEED,Set current playback speed,设置当前播放速度
PASSIVE_GROUP_TIMELINE,Point timeline,点时间轴
PASSIVE_GROUP_SIMULATOR,Simulator,模拟器
MOD_MOVE_OR_ADD_POINT,Click drag/add point in the timeline,在时间轴中点击拖拽/添加点
MOD_CLICK_SIM_ADD_PONT,Click simulator to add a point,"点击模拟器添加点"
PROJECT_HAS_UNSAVED_EDITS,Project has unsaved edits,项目有未保存的编辑
UNSAVED_EDITS_MSG,The current project has unsaved edits.,当前项目有未保存的编辑。
UNSAVED_CHANGES,Unsaved changes,未保存的更改
UNSAVED_CHANGES_MSG,Do you want to save and exit?,你想要保存并退出吗?
FILE_NOT_FOUND,File not found,文件未找到
COULDNT_FIND_FILE,Couldn't find file,找不到文件
OFS_FAILED_TO_IMPORT,OpenFunscripter failed to import.,OpenFunscripter导入失败。
OFS_FAILED_TO_IMPORT_MSG,Failed to import,导入失败
FAILED_TO_LOAD,Failed to load,加载失败
FAILED_TO_LOAD_MSG,The project failed to load.,项目加载失败。
FAILED_TO_FIND_VIDEO,Failed to find video,找不到视频
FAILED_TO_FIND_VIDEO_MSG,"The video was not found.
Please pick the correct video.","找不到视频。
请选择正确的视频。"
CHOOSE_OUTPUT_DIR,Choose output directory,选择输出目录
PICK_DIFFERENT_MEDIA,Pick different media,选择不同的媒体
FILE,File,文件
OPEN_PROJECT,Open project,打开项目
SAVE,Save,保存
CLOSE_PROJECT,Close project,关闭项目
WRONG_FILE,Wrong file,错误的文件
WRONG_FILE_MSG,The file isn't a project file.,该文件不是项目文件
IMPORT_VIDEO_SCRIPT,Import video/script,导入视频/脚本
RECENT_FILES,Recent files,最近的文件
NO_RECENT_FILES,No recent files,没有最近的文件
SAVE_PROJECT,Save project,保存项目
EXPORT_MENU,Export...,导出...
QUICK_EXPORT,Quick export,快速导出
QUICK_EXPORT_TOOLTIP,Exports all scripts as .funscript in their default paths.,将所有脚本导出为默认路径中的.funscript文件。
EXPORT_ACTIVE_SCRIPT,Export active script,导出活动脚本
EXPORT_ALL,Export all,导出全部
AUTO_BACKUP_TIMER_FMT,Auto Backup in %d seconds,%d秒后自动备份
AUTO_BACKUP,Auto Backup,自动备份
OPEN_BACKUP_DIR,Open backup directory,打开备份目录
CONFIGURE,Configure,配置
ADD_MENU,Add...,添加...
ADD_SHORTCUTS,Shortcuts,快捷键
ADD_NEW,Add new,添加新的
ADD_NEW_FUNSCRIPT,Add new funscript,添加新的funscript
ADD_EXISTING,Add existing,添加现有的
ADD_EXISTING_FUNSCRIPTS,Add existing funscripts,添加现有的funscript
REMOVE_SCRIPT_CONFIRM_MSG,"If the script wasn't previously exported, this can't be reverted.
Continue?","如果脚本之前没有导出,则无法恢复。
继续吗?"
REMOVE,Remove,移除
REMOVE_SCRIPT,Remove script,移除脚本
EDIT,Edit,编辑
SAVE_FRAME_AS_IMAGE,Save frame as image,保存帧为图像
OPEN_SCREENSHOT_DIR,Open screenshot directory,打开截图目录
SAVE_HEATMAP,Save heatmap,保存热图
UNDO,Undo,撤销
REDO,Redo,重做
CUT,Cut,剪切
PASTE,Paste,粘贴
SELECT,Select,选择
SELECT_ALL,Select all,全选
DESELECT_ALL,Deselect all,取消全选
SPECIAL,Special,特殊
SELECT_ALL_LEFT,Select all left,选择左侧全部
SELECT_ALL_RIGHT,Select all right,选择右侧全部
SET_SELECTION_START,Set selection start,设置选择开始
SET_SELECTION_END,Set selection end,设置选择结束
TOP_POINTS_ONLY,Top points only,仅顶部点
MID_POINTS_ONLY,Mid points only,仅中间点
BOTTOM_POINTS_ONLY,Bottom points only,仅底部点
BOOKMARKS,Bookmarks,书签
EXPORT_CLIPS,Export clips,导出片段
EXPORT_CLIPS_TOOLTIP,Export smaller clips based on bookmarks.,"基于书签导出较小的片段。"
NAME,Name,名称
ADD_BOOKMARK,Add bookmark,添加书签
CREATE_INTERVAL_FOR_FMT,"Create interval for ""%s""","为 ""%s"" 创建间隔"
GO_TO_MENU,Go to...,转到...
NO_BOOKMARKS,No bookmarks,没有书签
ALWAYS_SHOW_LABELS,Always show labels,始终显示标签
DELETE_ALL_BOOKMARKS,Delete all bookmarks,删除所有书签
VIEW_MENU,View,视图
SIMULATOR_3D,Simulator 3D,3D模拟器
METADATA,Metadata,元数据
DRAW_VIDEO,Draw video,绘制视频
RESET_VIDEO_POS,Reset video position,重置视频位置
VIDEO_MODE,Video mode,视频模式
VIDEO_MODE_FULL,Full,完整
VIDEO_MODE_LEFT_PANE,Left pane,左侧面板
VIDEO_MODE_RIGHT_PANE,Right pane,右侧面板
VIDEO_MODE_TOP_PANE,Top pane,顶部面板
VIDEO_MODE_BOTTOM_PANE,Bottom pane,底部面板
VIDEO_MODE_VR,VR,VR
DEBUG,Debug,调试
METRICS,Metrics,指标
LOG_OUTPUT,Log output,日志输出
FULLSCREEN,Fullscreen,全屏
PREFERENCES,Preferences,首选项
REPEAT_RATE,Repeat rate,重复率
CONTROLLER_CONNECTED,Controller connected!,控制器已连接!
EXTENSIONS_MENU,Extensions,扩展
DEV_MODE,Developer mode,开发者模式
SHOW_LOGS,Show logs,显示日志
DEV_MODE_TOOLTIP,Enable extra functionality for extension developement.,启用扩展开发的额外功能。
EXTENSION_DIR,Extension directory,扩展目录
ENABLED,Enabled,已启用
SHOW_WINDOW,Show window,显示窗口
OPEN_DIRECTORY,Open directory,打开目录
NAVIGATION,Navigation,导航
SCRIPTING,Scripting,脚本编写
UNSAVED_CHANGES_FMT,unsaved changes %d minutes ago,%d分钟前的未保存更改
METADATA_EDITOR,Metadate editor,元数据编辑器
TITLE,Title,标题
DURATION,Duration,持续时间
CREATOR,Creator,创建者
URL,Url,网址
VIDEO_URL,Video url,视频网址
NOTES,Notes,备注
LICENSE,License,许可证
FREE,Free,免费
PAID,Paid,付费
NONE,None,无
TAGS,Tags,标签
ADD,Add,添加
PERFORMERS,Performers,表演者
SAVE_TEMPLATE,Save template,保存模板
SAVE_TEMPLATE_TOOLTIP,Saves all current values as defaults for later.,将所有当前值保存为默认值以供以后使用。
GIT_COMMIT,Commit,提交
INTERVAL,Interval,间隔
CLOSE_WITHOUT_SAVING,Close without saving?,不保存就关闭?
CLOSE_WITHOUT_SAVING_MSG,The current project has unsaved changes do you want to close it without saving?,当前项目有未保存的更改,你想不保存就关闭吗?
CONFIGURATION,Configuration,配置
RESET,Reset,重置
MOVE,Move,移动
DISTANCE,Distance,距离
GLOBAL_YAW,Global yaw,全局偏航
GLOBAL_PITCH,Global pitch,全局俯仰
BOX,Box,盒子
CONTAINER,Container,容器
TWIST,Twist,扭转
ROLL_DEG,Roll deg,翻滚角度
PITCH_DEG,Pitch deg,俯仰角度
TWIST_DEG,Twist deg,扭转角度
ROLL,Roll,翻滚
PITCH,Pitch,俯仰
YAW,Yaw,偏航
INSERT_CURRENT_POSITION,Insert current position,插入当前位置
SCROLL_PERCENT,Scroll (%),滚动 (%)
SCROLL_PERCENT_TOOLTIP,You can use the mousewheel on the sliders above.,你可以在上面的滑块上使用鼠标滚轮。
EXTENSION_LOG_OUTPUT,Extension log output,扩展日志输出
ERROR_STR,Error,错误
TRY_RELOADING,Try reloading,尝试重新加载
RELOAD,Reload,重新加载
BPM,BPM,BPM
OFFSET,Offset,偏移
SNAP,Snap,对齐
UNKNOWN_ERROR,unknown error,未知错误
FFMPEG_WAS_NOT_FOUND_MSG,"ffmpeg.exe was not found.
Do you want to download it?","找不到ffmpeg.exe。
你想要下载它吗?"
BINDABLE_FUNCTIONS,Bindable functions,"可绑定的功能"
YES,Yes,是
FFMPEG_FAILED_TO_DOWNLOAD_MSG,Failed to download from https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip,从 https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip 下载失败
DONE,Done,完成
DONE_MSG,ffmpeg.exe was successfully extracted.,ffmpeg.exe已成功提取。
EXTRACT_FAIL,Failed to extract ffmpeg.exe.,提取ffmpeg.exe失败。
EXTRACT_FAIL_MSG,"Extracting uses tar.exe.
It will fail if it's not on your system.","提取使用tar.exe。
如果你的系统上没有它,提取将失败。"
DOWNLOAD_FFMPEG,Download ffmpeg?,下载ffmpeg
TEMPO_WHOLE_MEASURES,whole measures,整小节
TEMPO_2ND_MEASURES,2nd measures,二分小节
TEMPO_4TH_MEASURES,4th measures,四分小节
TEMPO_8TH_MEASURES,8th measures,八分小节
TEMPO_12TH_MEASURES,12th measures,十二分小节
TEMPO_16TH_MEASURES,16th measures,十六分小节
TEMPO_24TH_MEASURES,24th measures,二十四分小节
TEMPO_32ND_MEASURES,32nd measures,三十二分小节
TEMPO_48TH_MEASURES,48th measures,四十八分小节
TEMPO_64TH_MEASURES,64th measures,六十四分小节
LOAD_CONFIG,Load config,加载配置
SAVE_CONFIG,Save config,保存配置
SAVE_SIMULATOR_CONFIG,Save simulator configuration,保存模拟器配置
SAVE_SIMULATOR_CONFIG_MSG,"Do you want do save the current config?
This will override any existing default config.","你想要保存当前配置吗?
这将覆盖任何现有的默认配置。"
LINES,Lines,线条
TEXT,Text,文本
FRONT,Front,前面
BACK,Back,后面
BORDER,Border,边框
INDICATOR,Indicator,指示器
LINE,Line,线
WIDTH,Width,宽度
OPACITY,Opacity,不透明度
EXTRA_LINES,Extra lines,额外线条
VANILLA,Vanilla,原版
SHOW_POSITION,Show position,显示位置
VANILLA_TOOLTIP,The original simulator from day one.,第一天的原始模拟器。
RESET_TO_DEFAULTS,Reset to defaults,重置为默认值
SIMULATOR,Simulator,模拟器
APPLICATION,Application,应用程序
DARK_MODE,Dark mode,深色模式
LIGHT_MODE,Light mode,浅色模式
PREFERENCES_TXT,"Higher frame rate makes OFS feel ""snappier"" because input gets processed more frequently.","更高的帧率使OFS感觉更加"灵敏",因为输入处理更频繁。"
VSYNC,Vsync,垂直同步
VSYNC_TOOLTIP,"Limits frame rate to the refresh rate of the monitor.
Frame limit is ignored.","将帧率限制为显示器的刷新率。
忽略帧率限制。"
FRAME_LIMIT,Frame limit,帧率限制
FRAME_LIMIT_TOOLTIP,This limits the frame rate OFS is running at.,"这限制了OFS运行的帧率。"
FONT,Font,字体
CHANGE,Change,更改
CHOOSE_FONT,Choose font,选择字体
DEFAULT_FONT,Default font,默认字体
FONT_SIZE,Font size,字体大小
FORCE_HW_DECODING,Force hardware decoding (Requires program restart),强制硬件解码(需要重启程序)
FORCE_HW_DECODING_TOOLTIP,May cause crashes on some systems.,可能在某些系统上引起崩溃。
FAST_FRAME_STEP,Fast frame step,快速帧步进
FAST_FRAME_STEP_TOOLTIP,Amount of frames to skip with fast step.,快速步进时跳过的帧数。
SHOW_METADATA_DIALOG_ON_NEW_PROJECT,Show metadata dialog on new project,在新项目时显示元数据对话框。
FUNCTIONS_RANGE_EXTENDER,Range extender,范围扩展器
FUNCTIONS_SIMPLIFY,Simplify (Ramer-Douglas-Peucker),简化Ramer-Douglas-Peucker
RANGE,Range,范围
RANGE_EXTENDER_TXT,Select atleast 5 actions to extend.,选择至少5个动作以扩展。
EPSILON,Epsilon,Epsilon
SIMPLIFY_TXT,Select atleast 5 actions to simplify.,选择至少5个动作以简化。
SPECIAL_FUNCTIONS,Special functions,特殊功能
MEMORY_USAGE,Memory usage,内存使用
UPDATE,Update,更新
SLOWEST,slowest,最慢
LANGUAGE,Language,语言
Can't render this file because it contains an unexpected character in line 477 and column 145.

117
find_in_xlsx.py Normal file
View File

@ -0,0 +1,117 @@
"""
Excel文件内容查找工具
在指定文件夹中查找所有xlsx文件并搜索特定内容
"""
import os
from pathlib import Path
import openpyxl
from openpyxl.utils import get_column_letter
def find_text_in_xlsx(folder_path, search_text):
"""
在文件夹中所有xlsx文件里查找指定文本
Args:
folder_path: 要搜索的文件夹路径
search_text: 要查找的文本
Returns:
包含搜索结果的列表
"""
results = []
folder = Path(folder_path)
# 查找所有xlsx文件
xlsx_files = list(folder.rglob('*.xlsx'))
if not xlsx_files:
print(f"{folder_path} 中没有找到xlsx文件")
return results
print(f"找到 {len(xlsx_files)} 个xlsx文件开始搜索...\n")
for xlsx_file in xlsx_files:
# 跳过临时文件
if xlsx_file.name.startswith('~$'):
continue
try:
print(f"正在检查: {xlsx_file.name}")
workbook = openpyxl.load_workbook(xlsx_file, read_only=True, data_only=True)
# 遍历所有sheet
for sheet_name in workbook.sheetnames:
sheet = workbook[sheet_name]
# 遍历所有单元格
for row_idx, row in enumerate(sheet.iter_rows(), start=1):
for col_idx, cell in enumerate(row, start=1):
if cell.value is not None:
cell_value = str(cell.value)
if search_text in cell_value:
col_letter = get_column_letter(col_idx)
result = {
'file': str(xlsx_file),
'sheet': sheet_name,
'cell': f'{col_letter}{row_idx}',
'value': cell_value
}
results.append(result)
print(f" ✓ 找到: Sheet '{sheet_name}' - 单元格 {col_letter}{row_idx}: {cell_value}")
workbook.close()
except Exception as e:
print(f" ✗ 读取文件出错: {e}")
return results
def main():
print("=" * 60)
print("Excel文件内容查找工具")
print("=" * 60)
# 获取用户输入
folder_path = input("\n请输入要搜索的文件夹路径: ").strip().strip('"')
if not os.path.exists(folder_path):
print(f"错误: 文件夹 '{folder_path}' 不存在!")
return
if not os.path.isdir(folder_path):
print(f"错误: '{folder_path}' 不是一个文件夹!")
return
search_text = input("请输入要查找的内容 (默认: 101461): ").strip() or "101461"
print(f"\n开始在 '{folder_path}' 中搜索 '{search_text}'...\n")
print("-" * 60)
results = find_text_in_xlsx(folder_path, search_text)
print("\n" + "=" * 60)
print("搜索完成!")
print("=" * 60)
if results:
print(f"\n总共找到 {len(results)} 个匹配项:\n")
# 按文件分组显示结果
current_file = None
for result in results:
if result['file'] != current_file:
current_file = result['file']
print(f"\n文件: {Path(current_file).name}")
print(f"路径: {current_file}")
print(f" - Sheet: {result['sheet']}, 单元格: {result['cell']}, 内容: {result['value']}")
else:
print(f"\n未找到包含 '{search_text}' 的内容")
print("\n" + "=" * 60)
input("\n按回车键退出...")
if __name__ == "__main__":
main()

231
find_in_xlsx_gui.py Normal file
View File

@ -0,0 +1,231 @@
"""
Excel文件内容查找工具 - GUI版本
在指定文件夹中查找所有xlsx文件并搜索特定内容
"""
import os
import sys
from pathlib import Path
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import threading
import openpyxl
from openpyxl.utils import get_column_letter
class ExcelSearchApp:
def __init__(self, root):
self.root = root
self.root.title("Excel内容查找工具")
self.root.geometry("900x700")
self.is_searching = False
self.setup_ui()
def setup_ui(self):
"""设置界面"""
# 主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 配置权重
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
main_frame.rowconfigure(4, weight=1)
# 标题
title_label = ttk.Label(main_frame, text="Excel文件内容查找工具",
font=('Arial', 16, 'bold'))
title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
# 文件夹路径选择
ttk.Label(main_frame, text="文件夹路径:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.folder_var = tk.StringVar()
folder_entry = ttk.Entry(main_frame, textvariable=self.folder_var, width=50)
folder_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), padx=5, pady=5)
ttk.Button(main_frame, text="浏览...", command=self.browse_folder).grid(
row=1, column=2, padx=5, pady=5)
# 搜索文本
ttk.Label(main_frame, text="搜索内容:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.search_var = tk.StringVar(value="101461")
search_entry = ttk.Entry(main_frame, textvariable=self.search_var, width=50)
search_entry.grid(row=2, column=1, sticky=(tk.W, tk.E), padx=5, pady=5)
# 搜索按钮
self.search_btn = ttk.Button(main_frame, text="开始搜索",
command=self.start_search, style='Accent.TButton')
self.search_btn.grid(row=2, column=2, padx=5, pady=5)
# 进度条
self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
self.progress.grid(row=3, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)
# 结果显示区域
result_frame = ttk.LabelFrame(main_frame, text="搜索结果", padding="5")
result_frame.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
result_frame.columnconfigure(0, weight=1)
result_frame.rowconfigure(0, weight=1)
self.result_text = scrolledtext.ScrolledText(result_frame, wrap=tk.WORD,
width=80, height=25)
self.result_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 状态栏
self.status_var = tk.StringVar(value="就绪")
status_bar = ttk.Label(main_frame, textvariable=self.status_var,
relief=tk.SUNKEN, anchor=tk.W)
status_bar.grid(row=5, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=(5, 0))
def browse_folder(self):
"""浏览文件夹"""
folder = filedialog.askdirectory(title="选择要搜索的文件夹")
if folder:
self.folder_var.set(folder)
def log_message(self, message):
"""在结果区域显示消息"""
self.result_text.insert(tk.END, message + "\n")
self.result_text.see(tk.END)
self.root.update_idletasks()
def start_search(self):
"""开始搜索"""
folder_path = self.folder_var.get().strip()
search_text = self.search_var.get().strip()
if not folder_path:
messagebox.showwarning("警告", "请先选择文件夹!")
return
if not os.path.exists(folder_path):
messagebox.showerror("错误", f"文件夹不存在: {folder_path}")
return
if not search_text:
messagebox.showwarning("警告", "请输入要搜索的内容!")
return
# 清空结果区域
self.result_text.delete(1.0, tk.END)
# 禁用搜索按钮,启动进度条
self.search_btn.config(state='disabled')
self.progress.start(10)
self.is_searching = True
# 在新线程中执行搜索
search_thread = threading.Thread(
target=self.search_thread_func,
args=(folder_path, search_text),
daemon=True
)
search_thread.start()
def search_thread_func(self, folder_path, search_text):
"""搜索线程函数"""
try:
self.status_var.set("正在搜索...")
self.log_message("=" * 80)
self.log_message(f"开始在 '{folder_path}' 中搜索 '{search_text}'...")
self.log_message("=" * 80)
self.log_message("")
results = self.find_text_in_xlsx(folder_path, search_text)
self.log_message("")
self.log_message("=" * 80)
self.log_message("搜索完成!")
self.log_message("=" * 80)
self.log_message("")
if results:
self.log_message(f"总共找到 {len(results)} 个匹配项:\n")
# 按文件分组显示结果
current_file = None
for result in results:
if result['file'] != current_file:
current_file = result['file']
self.log_message(f"\n文件: {Path(current_file).name}")
self.log_message(f"路径: {current_file}")
self.log_message(f" - Sheet: {result['sheet']}, "
f"单元格: {result['cell']}, "
f"内容: {result['value']}")
self.status_var.set(f"搜索完成 - 找到 {len(results)} 个匹配项")
else:
self.log_message(f"未找到包含 '{search_text}' 的内容")
self.status_var.set("搜索完成 - 未找到匹配项")
except Exception as e:
self.log_message(f"\n错误: {str(e)}")
self.status_var.set("搜索出错")
messagebox.showerror("错误", f"搜索过程中出错:\n{str(e)}")
finally:
# 恢复按钮状态,停止进度条
self.search_btn.config(state='normal')
self.progress.stop()
self.is_searching = False
def find_text_in_xlsx(self, folder_path, search_text):
"""在文件夹中所有xlsx文件里查找指定文本"""
results = []
folder = Path(folder_path)
# 查找所有xlsx文件
xlsx_files = list(folder.rglob('*.xlsx'))
if not xlsx_files:
self.log_message(f"{folder_path} 中没有找到xlsx文件")
return results
self.log_message(f"找到 {len(xlsx_files)} 个xlsx文件开始搜索...\n")
for xlsx_file in xlsx_files:
# 跳过临时文件
if xlsx_file.name.startswith('~$'):
continue
try:
self.log_message(f"正在检查: {xlsx_file.name}")
workbook = openpyxl.load_workbook(xlsx_file, read_only=True, data_only=True)
# 遍历所有sheet
for sheet_name in workbook.sheetnames:
sheet = workbook[sheet_name]
# 遍历所有单元格
for row_idx, row in enumerate(sheet.iter_rows(), start=1):
for col_idx, cell in enumerate(row, start=1):
if cell.value is not None:
cell_value = str(cell.value)
if search_text in cell_value:
col_letter = get_column_letter(col_idx)
result = {
'file': str(xlsx_file),
'sheet': sheet_name,
'cell': f'{col_letter}{row_idx}',
'value': cell_value
}
results.append(result)
self.log_message(f" ✓ 找到: Sheet '{sheet_name}' - "
f"单元格 {col_letter}{row_idx}: {cell_value}")
workbook.close()
except Exception as e:
self.log_message(f" ✗ 读取文件出错: {e}")
return results
def main():
root = tk.Tk()
app = ExcelSearchApp(root)
root.mainloop()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,97 @@
# Excel内容查找工具使用说明
## 功能介绍
这个工具可以帮助你在指定文件夹中的所有Excel文件.xlsx中搜索特定内容并告诉你这些内容出现在哪些文件、哪些sheet、哪些单元格中。
## 文件说明
- **find_in_xlsx.py** - 命令行版本(在控制台运行)
- **find_in_xlsx_gui.py** - 图形界面版本(更方便使用)
## 安装依赖
在使用前需要安装openpyxl库
```bash
pip install openpyxl
```
## 使用方法
### 方法1使用图形界面版本推荐
1. 双击运行 `find_in_xlsx_gui.py`
2. 点击"浏览"按钮选择要搜索的文件夹
3. 输入要搜索的内容(默认是"101461"
4. 点击"开始搜索"按钮
5. 等待搜索完成,结果会显示在下方的文本框中
### 方法2使用命令行版本
1. 打开命令行窗口
2. 运行命令:
```bash
python find_in_xlsx.py
```
3. 按提示输入文件夹路径
4. 输入要搜索的内容(默认是"101461"
5. 等待搜索完成,查看结果
## 功能特点
- ✅ 递归搜索会搜索指定文件夹及其所有子文件夹中的xlsx文件
- ✅ 全面扫描检查每个Excel文件中的所有sheet
- ✅ 精确定位显示匹配内容所在的文件名、sheet名称、单元格位置和具体内容
- ✅ 进度显示:实时显示正在检查的文件
- ✅ 错误处理:遇到无法读取的文件会跳过并提示
- ✅ 友好界面GUI版本提供直观的操作界面
## 搜索结果示例
```
找到 3 个xlsx文件开始搜索...
正在检查: 数据表1.xlsx
✓ 找到: Sheet 'Sheet1' - 单元格 B5: 101461
✓ 找到: Sheet 'Sheet2' - 单元格 C10: ID: 101461
正在检查: 报表.xlsx
✓ 找到: Sheet '汇总' - 单元格 A15: 101461
========================================
搜索完成!
========================================
总共找到 3 个匹配项:
文件: 数据表1.xlsx
路径: E:\数据\数据表1.xlsx
- Sheet: Sheet1, 单元格: B5, 内容: 101461
- Sheet: Sheet2, 单元格: C10, 内容: ID: 101461
文件: 报表.xlsx
路径: E:\数据\报表.xlsx
- Sheet: 汇总, 单元格: A15, 内容: 101461
```
## 注意事项
1. 工具会自动跳过以 `~$` 开头的临时文件
2. 搜索是大小写敏感的
3. 只会搜索单元格的值,不会搜索公式
4. 如果Excel文件被其他程序打开可能会导致读取失败
## 常见问题
**Q: 提示"No module named 'openpyxl'"**
A: 需要先安装openpyxl`pip install openpyxl`
**Q: 搜索速度慢?**
A: 这取决于文件夹中Excel文件的数量和大小文件越多越大搜索时间越长
**Q: 能搜索公式吗?**
A: 目前只搜索单元格的显示值,不搜索公式本身
**Q: 支持.xls格式吗**
A: 目前只支持.xlsx格式不支持旧版.xls格式

252
jpg_to_png_converter.py Normal file
View File

@ -0,0 +1,252 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
JPG转PNG格式转换器
功能
1. 单个文件转换
2. 批量文件夹转换
3. 保持图片质量
4. 可选择是否删除原文件
"""
import os
import sys
from pathlib import Path
from PIL import Image
import argparse
class ImageConverter:
def __init__(self):
"""初始化图像转换器"""
self.supported_formats = ['.jpg', '.jpeg', '.JPG', '.JPEG']
self.converted_count = 0
self.failed_count = 0
self.failed_files = []
def convert_single_image(self, input_path: Path, output_path: Path = None, quality: int = 95) -> bool:
"""
转换单个JPG图片为PNG
Args:
input_path: 输入文件路径
output_path: 输出文件路径可选
quality: 图片质量对PNG无效但保留参数
Returns:
bool: 转换是否成功
"""
try:
# 检查输入文件是否存在
if not input_path.exists():
print(f"❌ 文件不存在: {input_path}")
return False
# 检查文件格式
if input_path.suffix.lower() not in [ext.lower() for ext in self.supported_formats]:
print(f"❌ 不支持的格式: {input_path.suffix}")
return False
# 设置输出路径
if output_path is None:
output_path = input_path.with_suffix('.png')
# 确保输出目录存在
output_path.parent.mkdir(parents=True, exist_ok=True)
print(f"🔄 转换中: {input_path.name} -> {output_path.name}")
# 打开并转换图片
with Image.open(input_path) as img:
# 如果是RGBA模式直接保存
# 如果是RGB模式转换为RGBA以支持透明度
if img.mode in ('RGBA', 'LA'):
# 已经有透明通道
img.save(output_path, 'PNG', optimize=True)
else:
# 转换为RGBA模式
if img.mode == 'P':
# 调色板模式转换为RGBA
img = img.convert('RGBA')
elif img.mode in ('RGB', 'L'):
# RGB或灰度模式转换为RGBA
img = img.convert('RGBA')
img.save(output_path, 'PNG', optimize=True)
print(f"✅ 转换成功: {output_path}")
self.converted_count += 1
return True
except Exception as e:
print(f"❌ 转换失败 {input_path}: {e}")
self.failed_count += 1
self.failed_files.append(str(input_path))
return False
def convert_folder(self, folder_path: Path, output_folder: Path = None,
delete_original: bool = False, recursive: bool = True) -> None:
"""
批量转换文件夹中的JPG图片
Args:
folder_path: 输入文件夹路径
output_folder: 输出文件夹路径可选
delete_original: 是否删除原文件
recursive: 是否递归处理子文件夹
"""
if not folder_path.exists():
print(f"❌ 文件夹不存在: {folder_path}")
return
if not folder_path.is_dir():
print(f"❌ 不是有效的文件夹: {folder_path}")
return
print(f"📁 开始处理文件夹: {folder_path}")
# 获取所有JPG文件
if recursive:
jpg_files = []
for ext in self.supported_formats:
jpg_files.extend(folder_path.rglob(f"*{ext}"))
else:
jpg_files = []
for ext in self.supported_formats:
jpg_files.extend(folder_path.glob(f"*{ext}"))
if not jpg_files:
print("📷 未找到JPG文件")
return
print(f"📷 找到 {len(jpg_files)} 个JPG文件")
# 转换每个文件
for jpg_file in jpg_files:
# 计算输出路径
if output_folder:
# 保持相对目录结构
relative_path = jpg_file.relative_to(folder_path)
output_path = output_folder / relative_path.with_suffix('.png')
else:
# 在原目录生成PNG文件
output_path = jpg_file.with_suffix('.png')
# 转换文件
success = self.convert_single_image(jpg_file, output_path)
# 如果转换成功且需要删除原文件
if success and delete_original:
try:
jpg_file.unlink()
print(f"🗑️ 已删除原文件: {jpg_file}")
except Exception as e:
print(f"⚠️ 删除原文件失败 {jpg_file}: {e}")
def print_summary(self) -> None:
"""打印转换摘要"""
total = self.converted_count + self.failed_count
print("\n" + "="*50)
print("🎯 转换摘要")
print(f"📊 总文件数: {total}")
print(f"✅ 成功转换: {self.converted_count}")
print(f"❌ 转换失败: {self.failed_count}")
if self.failed_files:
print("\n❌ 失败的文件:")
for file in self.failed_files:
print(f" - {file}")
print("="*50)
def main():
"""主函数"""
parser = argparse.ArgumentParser(description='JPG转PNG格式转换器')
parser.add_argument('input', help='输入文件或文件夹路径')
parser.add_argument('-o', '--output', help='输出文件或文件夹路径(可选)')
parser.add_argument('-d', '--delete', action='store_true', help='转换后删除原文件')
parser.add_argument('-r', '--recursive', action='store_true', default=True, help='递归处理子文件夹(默认启用)')
parser.add_argument('--no-recursive', action='store_true', help='不递归处理子文件夹')
# 如果没有命令行参数,使用交互模式
if len(sys.argv) == 1:
print("🎨 JPG转PNG格式转换器")
print("="*40)
# 输入路径
input_path = input("请输入JPG文件或文件夹路径: ").strip().strip('"')
if not input_path:
print("❌ 未输入路径,退出程序")
return
input_path = Path(input_path)
# 输出路径(可选)
output_input = input("输出路径(留空为原位置转换): ").strip().strip('"')
output_path = Path(output_input) if output_input else None
# 是否删除原文件
delete_original = input("转换后删除原JPG文件吗(y/N): ").strip().lower() == 'y'
# 是否递归处理
if input_path.is_dir():
recursive = input("递归处理子文件夹吗?(Y/n): ").strip().lower() != 'n'
else:
recursive = False
converter = ImageConverter()
if input_path.is_file():
# 单文件转换
converter.convert_single_image(input_path, output_path)
elif input_path.is_dir():
# 文件夹批量转换
converter.convert_folder(input_path, output_path, delete_original, recursive)
else:
print(f"❌ 路径不存在: {input_path}")
return
converter.print_summary()
else:
# 命令行模式
args = parser.parse_args()
input_path = Path(args.input)
output_path = Path(args.output) if args.output else None
delete_original = args.delete
recursive = args.recursive and not args.no_recursive
converter = ImageConverter()
if input_path.is_file():
converter.convert_single_image(input_path, output_path)
elif input_path.is_dir():
converter.convert_folder(input_path, output_path, delete_original, recursive)
else:
print(f"❌ 路径不存在: {input_path}")
return
converter.print_summary()
def quick_convert_demo():
"""快速转换演示函数"""
print("🚀 快速转换模式")
# 示例用法
converter = ImageConverter()
# 转换单个文件
# converter.convert_single_image(Path("example.jpg"))
# 批量转换文件夹
# converter.convert_folder(Path("./images"))
print("请修改代码中的路径后使用")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n❌ 用户中断操作")
except Exception as e:
print(f"❌ 程序运行错误: {e}")

447
jpg_to_png_gui.py Normal file
View File

@ -0,0 +1,447 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
JPG转PNG转换器 - GUI版本
使用tkinter创建图形界面支持文件和文件夹选择
"""
import os
import sys
import threading
from pathlib import Path
from tkinter import *
from tkinter import ttk, filedialog, messagebox
from tkinter.scrolledtext import ScrolledText
from PIL import Image
import datetime
class JPGtoPNGConverterGUI:
def __init__(self, root):
self.root = root
self.root.title("JPG转PNG转换器 v1.0")
self.root.geometry("800x600")
self.root.resizable(True, True)
# 设置窗口图标(如果需要)
try:
# 可以设置窗口图标
pass
except:
pass
# 变量
self.input_path = StringVar()
self.output_path = StringVar()
self.conversion_mode = StringVar(value="folder") # "file" 或 "folder"
self.delete_original = BooleanVar(value=False)
self.recursive = BooleanVar(value=True)
self.is_converting = False
# 统计变量
self.total_files = 0
self.converted_files = 0
self.failed_files = 0
self.create_widgets()
def create_widgets(self):
"""创建界面组件"""
# 主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(W, E, N, S))
# 配置网格权重
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(1, weight=1)
# 标题
title_label = ttk.Label(main_frame, text="🎨 JPG转PNG转换器", font=("Arial", 16, "bold"))
title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
# 转换模式选择
mode_frame = ttk.LabelFrame(main_frame, text="转换模式", padding="10")
mode_frame.grid(row=1, column=0, columnspan=3, sticky=(W, E), pady=(0, 10))
mode_frame.columnconfigure(0, weight=1)
ttk.Radiobutton(mode_frame, text="📁 转换文件夹(批量)",
variable=self.conversion_mode, value="folder",
command=self.on_mode_change).grid(row=0, column=0, sticky=W)
ttk.Radiobutton(mode_frame, text="📄 转换单个文件",
variable=self.conversion_mode, value="file",
command=self.on_mode_change).grid(row=0, column=1, sticky=W)
# 输入路径选择
input_frame = ttk.LabelFrame(main_frame, text="输入路径", padding="10")
input_frame.grid(row=2, column=0, columnspan=3, sticky=(W, E), pady=(0, 10))
input_frame.columnconfigure(1, weight=1)
ttk.Label(input_frame, text="输入:").grid(row=0, column=0, sticky=W, padx=(0, 5))
self.input_entry = ttk.Entry(input_frame, textvariable=self.input_path, width=50)
self.input_entry.grid(row=0, column=1, sticky=(W, E), padx=(0, 5))
self.input_browse_btn = ttk.Button(input_frame, text="浏览...", command=self.browse_input)
self.input_browse_btn.grid(row=0, column=2)
# 输出路径选择
output_frame = ttk.LabelFrame(main_frame, text="输出路径(可选)", padding="10")
output_frame.grid(row=3, column=0, columnspan=3, sticky=(W, E), pady=(0, 10))
output_frame.columnconfigure(1, weight=1)
ttk.Label(output_frame, text="输出:").grid(row=0, column=0, sticky=W, padx=(0, 5))
ttk.Entry(output_frame, textvariable=self.output_path, width=50).grid(row=0, column=1, sticky=(W, E), padx=(0, 5))
self.output_browse_btn = ttk.Button(output_frame, text="浏览...", command=self.browse_output)
self.output_browse_btn.grid(row=0, column=2)
ttk.Label(output_frame, text="💡 留空将在原位置生成PNG文件",
foreground="gray").grid(row=1, column=0, columnspan=3, sticky=W, pady=(5, 0))
# 选项设置
options_frame = ttk.LabelFrame(main_frame, text="转换选项", padding="10")
options_frame.grid(row=4, column=0, columnspan=3, sticky=(W, E), pady=(0, 10))
ttk.Checkbutton(options_frame, text="🗑️ 转换后删除原JPG文件",
variable=self.delete_original).grid(row=0, column=0, sticky=W)
self.recursive_check = ttk.Checkbutton(options_frame, text="📁 递归处理子文件夹",
variable=self.recursive)
self.recursive_check.grid(row=1, column=0, sticky=W)
# 控制按钮
button_frame = ttk.Frame(main_frame)
button_frame.grid(row=5, column=0, columnspan=3, pady=20)
self.start_btn = ttk.Button(button_frame, text="🚀 开始转换",
command=self.start_conversion, style="Accent.TButton")
self.start_btn.pack(side=LEFT, padx=(0, 10))
self.stop_btn = ttk.Button(button_frame, text="⏹️ 停止",
command=self.stop_conversion, state=DISABLED)
self.stop_btn.pack(side=LEFT, padx=(0, 10))
ttk.Button(button_frame, text="🗂️ 打开输出文件夹",
command=self.open_output_folder).pack(side=LEFT)
# 进度条
progress_frame = ttk.Frame(main_frame)
progress_frame.grid(row=6, column=0, columnspan=3, sticky=(W, E), pady=(0, 10))
progress_frame.columnconfigure(0, weight=1)
self.progress_var = DoubleVar()
self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var,
maximum=100, mode='determinate')
self.progress_bar.grid(row=0, column=0, sticky=(W, E), padx=(0, 5))
self.progress_label = ttk.Label(progress_frame, text="准备就绪")
self.progress_label.grid(row=0, column=1)
# 状态信息显示
status_frame = ttk.LabelFrame(main_frame, text="转换日志", padding="5")
status_frame.grid(row=7, column=0, columnspan=3, sticky=(W, E, N, S), pady=(0, 10))
status_frame.columnconfigure(0, weight=1)
status_frame.rowconfigure(0, weight=1)
self.log_text = ScrolledText(status_frame, height=12, wrap=WORD)
self.log_text.grid(row=0, column=0, sticky=(W, E, N, S))
# 配置主框架的行权重
main_frame.rowconfigure(7, weight=1)
# 初始化界面状态
self.on_mode_change()
def on_mode_change(self):
"""转换模式改变时的处理"""
if self.conversion_mode.get() == "file":
self.recursive_check.configure(state=DISABLED)
self.input_browse_btn.configure(text="选择文件...")
self.output_browse_btn.configure(text="保存为...")
else:
self.recursive_check.configure(state=NORMAL)
self.input_browse_btn.configure(text="选择文件夹...")
self.output_browse_btn.configure(text="选择文件夹...")
def browse_input(self):
"""浏览输入路径"""
if self.conversion_mode.get() == "file":
# 选择文件
file_path = filedialog.askopenfilename(
title="选择JPG文件",
filetypes=[
("JPG文件", "*.jpg *.jpeg *.JPG *.JPEG"),
("所有文件", "*.*")
]
)
if file_path:
self.input_path.set(file_path)
else:
# 选择文件夹
folder_path = filedialog.askdirectory(title="选择包含JPG文件的文件夹")
if folder_path:
self.input_path.set(folder_path)
def browse_output(self):
"""浏览输出路径"""
if self.conversion_mode.get() == "file":
# 保存文件
file_path = filedialog.asksaveasfilename(
title="保存PNG文件为",
defaultextension=".png",
filetypes=[
("PNG文件", "*.png"),
("所有文件", "*.*")
]
)
if file_path:
self.output_path.set(file_path)
else:
# 选择输出文件夹
folder_path = filedialog.askdirectory(title="选择输出文件夹")
if folder_path:
self.output_path.set(folder_path)
def log_message(self, message):
"""添加日志信息"""
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
self.log_text.insert(END, f"[{timestamp}] {message}\n")
self.log_text.see(END)
self.root.update_idletasks()
def update_progress(self, current, total, status=""):
"""更新进度条"""
if total > 0:
progress = (current / total) * 100
self.progress_var.set(progress)
if status:
self.progress_label.configure(text=status)
else:
self.progress_label.configure(text=f"{current}/{total}")
self.root.update_idletasks()
def convert_single_file(self, input_file, output_file=None):
"""转换单个文件"""
try:
input_path = Path(input_file)
if not input_path.exists():
self.log_message(f"❌ 文件不存在: {input_file}")
return False
# 设置输出路径
if output_file:
output_path = Path(output_file)
else:
output_path = input_path.with_suffix('.png')
# 确保输出目录存在
output_path.parent.mkdir(parents=True, exist_ok=True)
self.log_message(f"🔄 转换: {input_path.name} -> {output_path.name}")
# 转换图片
with Image.open(input_path) as img:
if img.mode in ('RGBA', 'LA'):
img.save(output_path, 'PNG', optimize=True)
else:
if img.mode == 'P':
img = img.convert('RGBA')
elif img.mode in ('RGB', 'L'):
img = img.convert('RGBA')
img.save(output_path, 'PNG', optimize=True)
self.log_message(f"✅ 转换成功: {output_path}")
self.converted_files += 1
# 删除原文件(如果选择)
if self.delete_original.get():
try:
input_path.unlink()
self.log_message(f"🗑️ 已删除原文件: {input_path}")
except Exception as e:
self.log_message(f"⚠️ 删除原文件失败: {e}")
return True
except Exception as e:
self.log_message(f"❌ 转换失败 {input_file}: {e}")
self.failed_files += 1
return False
def find_jpg_files(self, folder_path, recursive=True):
"""查找JPG文件"""
folder = Path(folder_path)
jpg_files = []
patterns = ['*.jpg', '*.jpeg', '*.JPG', '*.JPEG']
if recursive:
for pattern in patterns:
jpg_files.extend(folder.rglob(pattern))
else:
for pattern in patterns:
jpg_files.extend(folder.glob(pattern))
return jpg_files
def conversion_worker(self):
"""转换工作线程"""
try:
self.total_files = 0
self.converted_files = 0
self.failed_files = 0
input_path = self.input_path.get().strip()
output_path = self.output_path.get().strip()
if not input_path:
self.log_message("❌ 请选择输入路径")
return
if self.conversion_mode.get() == "file":
# 单文件转换
self.total_files = 1
self.update_progress(0, 1, "转换中...")
output_file = output_path if output_path else None
self.convert_single_file(input_path, output_file)
self.update_progress(1, 1, "完成")
else:
# 批量转换文件夹
self.log_message(f"📁 扫描文件夹: {input_path}")
jpg_files = self.find_jpg_files(input_path, self.recursive.get())
if not jpg_files:
self.log_message("📷 未找到JPG文件")
return
self.total_files = len(jpg_files)
self.log_message(f"📷 找到 {self.total_files} 个JPG文件")
# 转换每个文件
for i, jpg_file in enumerate(jpg_files):
if not self.is_converting: # 检查是否被停止
break
# 计算输出路径
if output_path:
relative_path = jpg_file.relative_to(Path(input_path))
output_file = Path(output_path) / relative_path.with_suffix('.png')
else:
output_file = None
self.update_progress(i, self.total_files, f"转换中 {i+1}/{self.total_files}")
self.convert_single_file(jpg_file, output_file)
self.update_progress(self.total_files, self.total_files, "完成")
# 显示转换摘要
self.log_message("=" * 50)
self.log_message(f"🎯 转换摘要")
self.log_message(f"📊 总文件数: {self.total_files}")
self.log_message(f"✅ 成功转换: {self.converted_files}")
self.log_message(f"❌ 转换失败: {self.failed_files}")
self.log_message("=" * 50)
if self.converted_files > 0:
messagebox.showinfo("转换完成",
f"转换完成!\n"
f"成功: {self.converted_files} 个文件\n"
f"失败: {self.failed_files} 个文件")
except Exception as e:
self.log_message(f"❌ 转换过程出错: {e}")
messagebox.showerror("错误", f"转换过程出错: {e}")
finally:
self.is_converting = False
self.start_btn.configure(state=NORMAL)
self.stop_btn.configure(state=DISABLED)
def start_conversion(self):
"""开始转换"""
if self.is_converting:
return
# 验证输入
if not self.input_path.get().strip():
messagebox.showerror("错误", "请选择输入路径")
return
if not Path(self.input_path.get()).exists():
messagebox.showerror("错误", "输入路径不存在")
return
# 清空日志
self.log_text.delete(1.0, END)
# 开始转换
self.is_converting = True
self.start_btn.configure(state=DISABLED)
self.stop_btn.configure(state=NORMAL)
# 在新线程中执行转换
threading.Thread(target=self.conversion_worker, daemon=True).start()
def stop_conversion(self):
"""停止转换"""
self.is_converting = False
self.log_message("⏹️ 用户停止转换")
self.start_btn.configure(state=NORMAL)
self.stop_btn.configure(state=DISABLED)
def open_output_folder(self):
"""打开输出文件夹"""
output_path = self.output_path.get().strip()
if output_path and Path(output_path).exists():
os.startfile(output_path)
elif self.input_path.get().strip():
input_path = self.input_path.get().strip()
if Path(input_path).exists():
if Path(input_path).is_file():
os.startfile(Path(input_path).parent)
else:
os.startfile(input_path)
else:
messagebox.showwarning("警告", "没有有效的输出路径")
def main():
"""主函数"""
root = Tk()
# 设置样式
style = ttk.Style()
# 尝试使用现代主题
try:
style.theme_use('winnative') # Windows原生样式
except:
pass
# 创建应用
app = JPGtoPNGConverterGUI(root)
# 设置窗口关闭事件
def on_closing():
if app.is_converting:
if messagebox.askokcancel("退出", "正在转换中,确定要退出吗?"):
app.is_converting = False
root.destroy()
else:
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
# 运行主循环
root.mainloop()
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"程序启动失败: {e}")
import traceback
traceback.print_exc()

View File

@ -0,0 +1,215 @@
# JPG转PNG转换器 - GUI版本使用说明
## 🎨 程序界面预览
GUI版本提供了直观的图形界面包含以下功能区域
### 📋 界面布局
```
┌─────────────────────────────────────────┐
│ 🎨 JPG转PNG转换器 v1.0 │
├─────────────────────────────────────────┤
│ 转换模式 │
│ ○ 📁 转换文件夹(批量) │
│ ● 📄 转换单个文件 │
├─────────────────────────────────────────┤
│ 输入路径 │
│ [文件路径________________] [浏览...] │
├─────────────────────────────────────────┤
│ 输出路径(可选) │
│ [输出路径________________] [浏览...] │
│ 💡 留空将在原位置生成PNG文件 │
├─────────────────────────────────────────┤
│ 转换选项 │
│ □ 🗑️ 转换后删除原JPG文件 │
│ ☑ 📁 递归处理子文件夹 │
├─────────────────────────────────────────┤
│ [🚀 开始转换] [⏹️ 停止] [🗂️ 打开输出文件夹] │
├─────────────────────────────────────────┤
│ 进度条: ████████████████████ 100% │
├─────────────────────────────────────────┤
│ 转换日志 │
│ ┌─────────────────────────────────────┐ │
│ │[12:34:56] 📁 扫描文件夹: C:\Images │ │
│ │[12:34:57] 📷 找到 5 个JPG文件 │ │
│ │[12:34:58] 🔄 转换: photo1.jpg │ │
│ │[12:34:59] ✅ 转换成功: photo1.png │ │
│ │... │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
```
## 🚀 使用步骤
### 1. 启动程序
```bash
cd e:\SelfSpace\pythontool
python jpg_to_png_gui.py
```
### 2. 选择转换模式
#### 📄 单文件转换
- 选择 "转换单个文件"
- 点击 "浏览..." 选择JPG文件
- 可选设置输出PNG文件位置
- 点击 "开始转换"
#### 📁 批量转换
- 选择 "转换文件夹(批量)"
- 点击 "浏览..." 选择包含JPG文件的文件夹
- 可选:设置输出文件夹
- 勾选 "递归处理子文件夹" 可处理所有子目录
- 点击 "开始转换"
### 3. 配置选项
#### 🗑️ 删除原文件
- 勾选此选项会在转换成功后删除原JPG文件
- ⚠️ **危险操作**:请谨慎使用,建议先备份重要文件
#### 📁 递归处理
- 仅在批量转换模式下可用
- 勾选后会处理所有子文件夹中的JPG文件
### 4. 监控进度
- **进度条**:显示当前转换进度
- **转换日志**:实时显示详细的转换信息
- **统计信息**:显示成功/失败文件数量
## 🎯 界面功能详解
### 🔘 控制按钮
| 按钮 | 功能 | 说明 |
|------|------|------|
| 🚀 开始转换 | 启动转换过程 | 验证输入后开始转换 |
| ⏹️ 停止 | 停止正在进行的转换 | 仅在转换中可用 |
| 🗂️ 打开输出文件夹 | 打开输出目录 | 方便查看转换结果 |
### 📊 状态显示
#### 进度条
- 显示当前转换进度百分比
- 显示 "当前文件/总文件" 信息
- 转换完成后显示 "完成"
#### 转换日志
- **时间戳**:每条消息都有时间标记
- **状态图标**
- 📁 文件夹操作
- 📷 文件统计
- 🔄 正在转换
- ✅ 转换成功
- ❌ 转换失败
- 🗑️ 文件删除
- ⚠️ 警告信息
## 🔧 高级功能
### 多线程处理
- GUI使用独立线程进行文件转换
- 界面不会在转换过程中卡死
- 可以随时停止转换过程
### 智能路径处理
- 自动处理相对路径结构
- 支持中文路径和文件名
- 自动创建输出目录
### 错误处理
- 详细的错误信息显示
- 转换失败不影响其他文件
- 完整的操作日志记录
## 💡 使用技巧
### 1. 路径选择
- **拖拽支持**:可以直接拖拽文件/文件夹到输入框(如果系统支持)
- **路径复制**:可以直接复制粘贴路径到输入框
- **引号处理**:程序会自动处理包含空格的路径
### 2. 批量处理策略
```
推荐处理顺序:
1. 先在小范围测试(少量文件)
2. 检查输出质量和文件大小
3. 确认无误后进行大批量处理
4. 重要文件建议先备份
```
### 3. 性能优化
- **大批量文件**:建议不要同时处理过多文件(建议<1000个
- **存储空间**确保有足够的磁盘空间PNG通常比JPG大
- **内存考虑**:超大图片可能消耗较多内存
## 📋 常见使用场景
### 场景1单张图片转换
```
1. 选择"转换单个文件"
2. 选择JPG文件
3. 点击开始转换
4. 在同目录下生成PNG文件
```
### 场景2整个文件夹转换
```
1. 选择"转换文件夹(批量)"
2. 选择包含JPG的文件夹
3. 勾选"递归处理子文件夹"
4. 点击开始转换
5. 所有JPG文件都会转换为PNG
```
### 场景3分类整理转换
```
1. 选择"转换文件夹(批量)"
2. 选择源文件夹
3. 设置专门的输出文件夹
4. 开始转换
5. 原文件保持不变PNG文件统一存放
```
## ⚠️ 注意事项
### 安全提醒
- ✅ **建议**:转换前备份重要图片
- ⚠️ **警告**:删除原文件选项不可恢复
- 💾 **存储**:确保足够的磁盘空间
### 性能注意
- 🔄 **大文件**:超大图片转换时间较长
- 💻 **内存**:同时处理多个大文件可能占用较多内存
- ⏸️ **暂停**:可随时停止转换过程
### 兼容性
- 🖥️ **系统**Windows 7及以上版本
- 🐍 **Python**Python 3.6及以上版本
- 📦 **依赖**需要安装Pillow库
## 🛠️ 故障排除
### 问题1程序无法启动
```bash
# 检查Python版本
python --version
# 安装依赖
pip install Pillow
```
### 问题2文件选择失败
- 检查文件路径是否正确
- 确认文件格式是JPG/JPEG
- 检查文件是否被其他程序占用
### 问题3转换失败
- 查看错误日志信息
- 检查输出目录是否有写入权限
- 确认输入文件没有损坏
### 问题4界面卡死
- 程序使用多线程,正常情况下不会卡死
- 如果卡死可能是处理超大文件,请等待
- 可以点击"停止"按钮中断转换

118
jpg_to_png_simple.py Normal file
View File

@ -0,0 +1,118 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
简化版JPG转PNG转换器
适合快速转换操作简单
"""
import os
from pathlib import Path
from PIL import Image
def convert_jpg_to_png(input_path, output_path=None):
"""
将JPG文件转换为PNG格式
Args:
input_path: 输入JPG文件路径
output_path: 输出PNG文件路径可选
"""
input_file = Path(input_path)
# 检查文件是否存在
if not input_file.exists():
print(f"❌ 文件不存在: {input_path}")
return False
# 设置输出路径
if output_path is None:
output_file = input_file.with_suffix('.png')
else:
output_file = Path(output_path)
try:
# 打开并转换图片
with Image.open(input_file) as img:
# 转换为RGBA模式支持透明度
if img.mode != 'RGBA':
img = img.convert('RGBA')
# 保存为PNG
img.save(output_file, 'PNG')
print(f"✅ 转换成功: {input_file.name} -> {output_file.name}")
return True
except Exception as e:
print(f"❌ 转换失败: {e}")
return False
def batch_convert_folder(folder_path):
"""
批量转换文件夹中的JPG文件
Args:
folder_path: 文件夹路径
"""
folder = Path(folder_path)
if not folder.exists() or not folder.is_dir():
print(f"❌ 文件夹不存在: {folder_path}")
return
# 找到所有JPG文件
jpg_files = list(folder.glob('*.jpg')) + list(folder.glob('*.JPG')) + \
list(folder.glob('*.jpeg')) + list(folder.glob('*.JPEG'))
if not jpg_files:
print("📷 未找到JPG文件")
return
print(f"📷 找到 {len(jpg_files)} 个JPG文件开始转换...")
success_count = 0
for jpg_file in jpg_files:
if convert_jpg_to_png(jpg_file):
success_count += 1
print(f"\n🎯 转换完成!成功转换 {success_count}/{len(jpg_files)} 个文件")
def main():
"""主函数"""
print("🎨 简化版JPG转PNG转换器")
print("=" * 30)
while True:
print("\n选择操作模式:")
print("1. 转换单个文件")
print("2. 批量转换文件夹")
print("3. 退出")
choice = input("请选择 (1-3): ").strip()
if choice == '1':
# 单文件转换
file_path = input("请输入JPG文件路径: ").strip().strip('"')
if file_path:
output_path = input("输出PNG路径留空为自动生成: ").strip().strip('"')
convert_jpg_to_png(file_path, output_path if output_path else None)
elif choice == '2':
# 批量转换
folder_path = input("请输入文件夹路径: ").strip().strip('"')
if folder_path:
batch_convert_folder(folder_path)
elif choice == '3':
print("👋 再见!")
break
else:
print("❌ 无效选择,请重新输入")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n👋 用户退出程序")
except Exception as e:
print(f"❌ 程序错误: {e}")

155
jpg_to_png使用说明.md Normal file
View File

@ -0,0 +1,155 @@
# JPG转PNG格式转换器使用说明
## 功能特性
- ✅ 单个文件转换
- ✅ 批量文件夹转换
- ✅ 递归处理子文件夹
- ✅ 保持图片质量
- ✅ 支持透明度处理
- ✅ 可选择删除原文件
- ✅ 详细的转换报告
## 支持格式
- 输入格式JPG, JPEG大小写不敏感
- 输出格式PNG
## 使用方法
### 1. 交互模式(推荐初学者)
直接运行脚本,按提示操作:
```bash
python jpg_to_png_converter.py
```
### 2. 命令行模式
```bash
# 转换单个文件
python jpg_to_png_converter.py image.jpg
# 转换单个文件到指定位置
python jpg_to_png_converter.py image.jpg -o output.png
# 批量转换文件夹
python jpg_to_png_converter.py ./images
# 批量转换到指定输出文件夹
python jpg_to_png_converter.py ./images -o ./png_output
# 转换后删除原文件
python jpg_to_png_converter.py ./images -d
# 不递归处理子文件夹
python jpg_to_png_converter.py ./images --no-recursive
```
## 命令行参数
- `input`: 输入文件或文件夹路径(必需)
- `-o, --output`: 输出文件或文件夹路径(可选)
- `-d, --delete`: 转换后删除原JPG文件
- `-r, --recursive`: 递归处理子文件夹(默认启用)
- `--no-recursive`: 不递归处理子文件夹
## 使用示例
### 示例1转换单个文件
```bash
python jpg_to_png_converter.py "C:\Users\Pictures\photo.jpg"
```
结果:在同一目录生成 `photo.png`
### 示例2批量转换文件夹
```bash
python jpg_to_png_converter.py "C:\Users\Pictures\vacation"
```
结果转换文件夹中所有JPG文件为PNG格式
### 示例3转换到指定目录
```bash
python jpg_to_png_converter.py "C:\Input" -o "C:\Output"
```
结果将Input文件夹的JPG文件转换为PNG并保存到Output文件夹
### 示例4转换后删除原文件
```bash
python jpg_to_png_converter.py "C:\Users\Pictures" -d
```
⚠️ **注意**原JPG文件将被永久删除
## 交互模式示例
```
🎨 JPG转PNG格式转换器
========================================
请输入JPG文件或文件夹路径: C:\Users\Pictures
输出路径(留空为原位置转换):
转换后删除原JPG文件吗(y/N): n
递归处理子文件夹吗?(Y/n): y
📁 开始处理文件夹: C:\Users\Pictures
📷 找到 15 个JPG文件
🔄 转换中: photo1.jpg -> photo1.png
✅ 转换成功: C:\Users\Pictures\photo1.png
...
==================================================
🎯 转换摘要
📊 总文件数: 15
✅ 成功转换: 15
❌ 转换失败: 0
==================================================
```
## 技术特性
### 图像质量
- 使用PIL/Pillow库确保高质量转换
- 自动处理不同颜色模式RGB、RGBA、P、L
- 启用PNG优化以减小文件大小
### 透明度处理
- 自动转换为RGBA模式以支持透明度
- 保持原有图像质量
### 错误处理
- 完善的异常处理机制
- 详细的错误信息显示
- 转换失败时继续处理其他文件
## 注意事项
⚠️ **重要提醒**
1. 使用 `-d` 参数会永久删除原JPG文件请谨慎使用
2. PNG文件通常比JPG文件大确保有足够的存储空间
3. 建议先在小范围测试后再进行大批量转换
## 依赖库
- `Pillow`: Python图像处理库
- `pathlib`: 路径处理Python内置
- `argparse`: 命令行参数解析Python内置
## 安装依赖
```bash
pip install Pillow
```
## 故障排除
### 问题1提示"无法解析导入PIL"
**解决方案**安装Pillow库
```bash
pip install Pillow
```
### 问题2转换后文件很大
**说明**PNG是无损格式文件通常比JPG大。这是正常现象。
### 问题3某些文件转换失败
**解决方案**
- 检查文件是否损坏
- 确认文件格式确实是JPG
- 查看详细错误信息
### 问题4路径包含空格或特殊字符
**解决方案**:使用引号包围路径
```bash
python jpg_to_png_converter.py "C:\My Photos\vacation pics"
```

View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['npm_publish_gui.py'],
pathex=[],
binaries=[],
datas=[('npm_publish_config.json', '.'), ('npm_publish_gui使用说明.md', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='NPM发布工具',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['果汁.png'],
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,328 @@
('E:\\SelfSpace\\pythontool\\build\\NPM发布工具\\PYZ-00.pyz',
[('_compat_pickle',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_compat_pickle.py',
'PYMODULE'),
('_compression',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_compression.py',
'PYMODULE'),
('_py_abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_py_abc.py',
'PYMODULE'),
('_pydecimal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_pydecimal.py',
'PYMODULE'),
('_strptime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_strptime.py',
'PYMODULE'),
('_threading_local',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_threading_local.py',
'PYMODULE'),
('argparse',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\argparse.py',
'PYMODULE'),
('ast',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ast.py',
'PYMODULE'),
('base64',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\base64.py',
'PYMODULE'),
('bisect',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bisect.py',
'PYMODULE'),
('bz2',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bz2.py',
'PYMODULE'),
('calendar',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\calendar.py',
'PYMODULE'),
('contextlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\contextlib.py',
'PYMODULE'),
('contextvars',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\contextvars.py',
'PYMODULE'),
('copy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\copy.py',
'PYMODULE'),
('csv',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\csv.py',
'PYMODULE'),
('dataclasses',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\dataclasses.py',
'PYMODULE'),
('datetime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\datetime.py',
'PYMODULE'),
('decimal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\decimal.py',
'PYMODULE'),
('dis',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\dis.py',
'PYMODULE'),
('email',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\__init__.py',
'PYMODULE'),
('email._encoded_words',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_encoded_words.py',
'PYMODULE'),
('email._header_value_parser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_header_value_parser.py',
'PYMODULE'),
('email._parseaddr',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_parseaddr.py',
'PYMODULE'),
('email._policybase',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_policybase.py',
'PYMODULE'),
('email.base64mime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\base64mime.py',
'PYMODULE'),
('email.charset',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\charset.py',
'PYMODULE'),
('email.contentmanager',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\contentmanager.py',
'PYMODULE'),
('email.encoders',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\encoders.py',
'PYMODULE'),
('email.errors',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\errors.py',
'PYMODULE'),
('email.feedparser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\feedparser.py',
'PYMODULE'),
('email.generator',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\generator.py',
'PYMODULE'),
('email.header',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\header.py',
'PYMODULE'),
('email.headerregistry',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\headerregistry.py',
'PYMODULE'),
('email.iterators',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\iterators.py',
'PYMODULE'),
('email.message',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\message.py',
'PYMODULE'),
('email.parser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\parser.py',
'PYMODULE'),
('email.policy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\policy.py',
'PYMODULE'),
('email.quoprimime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\quoprimime.py',
'PYMODULE'),
('email.utils',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\utils.py',
'PYMODULE'),
('fnmatch',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\fnmatch.py',
'PYMODULE'),
('fractions',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\fractions.py',
'PYMODULE'),
('getopt',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\getopt.py',
'PYMODULE'),
('gettext',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gettext.py',
'PYMODULE'),
('gzip',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gzip.py',
'PYMODULE'),
('hashlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\hashlib.py',
'PYMODULE'),
('importlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\__init__.py',
'PYMODULE'),
('importlib._abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_abc.py',
'PYMODULE'),
('importlib._bootstrap',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_bootstrap_external.py',
'PYMODULE'),
('importlib.abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\abc.py',
'PYMODULE'),
('importlib.machinery',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\machinery.py',
'PYMODULE'),
('importlib.metadata',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\__init__.py',
'PYMODULE'),
('importlib.metadata._adapters',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_adapters.py',
'PYMODULE'),
('importlib.metadata._collections',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_collections.py',
'PYMODULE'),
('importlib.metadata._functools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_functools.py',
'PYMODULE'),
('importlib.metadata._itertools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_itertools.py',
'PYMODULE'),
('importlib.metadata._meta',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_meta.py',
'PYMODULE'),
('importlib.metadata._text',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_text.py',
'PYMODULE'),
('importlib.readers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\readers.py',
'PYMODULE'),
('importlib.resources',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\__init__.py',
'PYMODULE'),
('importlib.resources._adapters',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_adapters.py',
'PYMODULE'),
('importlib.resources._common',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_common.py',
'PYMODULE'),
('importlib.resources._itertools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_itertools.py',
'PYMODULE'),
('importlib.resources._legacy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_legacy.py',
'PYMODULE'),
('importlib.resources.abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\abc.py',
'PYMODULE'),
('importlib.resources.readers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\readers.py',
'PYMODULE'),
('importlib.util',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\util.py',
'PYMODULE'),
('inspect',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\inspect.py',
'PYMODULE'),
('ipaddress',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ipaddress.py',
'PYMODULE'),
('json',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\__init__.py',
'PYMODULE'),
('json.decoder',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\decoder.py',
'PYMODULE'),
('json.encoder',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\encoder.py',
'PYMODULE'),
('json.scanner',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\scanner.py',
'PYMODULE'),
('logging',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\logging\\__init__.py',
'PYMODULE'),
('lzma',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\lzma.py',
'PYMODULE'),
('numbers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\numbers.py',
'PYMODULE'),
('opcode',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\opcode.py',
'PYMODULE'),
('pathlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pathlib.py',
'PYMODULE'),
('pickle',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pickle.py',
'PYMODULE'),
('pprint',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pprint.py',
'PYMODULE'),
('py_compile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\py_compile.py',
'PYMODULE'),
('quopri',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\quopri.py',
'PYMODULE'),
('random',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\random.py',
'PYMODULE'),
('selectors',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\selectors.py',
'PYMODULE'),
('shutil',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\shutil.py',
'PYMODULE'),
('signal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\signal.py',
'PYMODULE'),
('socket',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\socket.py',
'PYMODULE'),
('statistics',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\statistics.py',
'PYMODULE'),
('string',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\string.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stringprep.py',
'PYMODULE'),
('subprocess',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\subprocess.py',
'PYMODULE'),
('tarfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tarfile.py',
'PYMODULE'),
('tempfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tempfile.py',
'PYMODULE'),
('textwrap',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\textwrap.py',
'PYMODULE'),
('threading',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\threading.py',
'PYMODULE'),
('tkinter',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\__init__.py',
'PYMODULE'),
('tkinter.commondialog',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\commondialog.py',
'PYMODULE'),
('tkinter.constants',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\constants.py',
'PYMODULE'),
('tkinter.messagebox',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\messagebox.py',
'PYMODULE'),
('tkinter.scrolledtext',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\scrolledtext.py',
'PYMODULE'),
('tkinter.ttk',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\ttk.py',
'PYMODULE'),
('token',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\token.py',
'PYMODULE'),
('tokenize',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tokenize.py',
'PYMODULE'),
('tracemalloc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tracemalloc.py',
'PYMODULE'),
('typing',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\typing.py',
'PYMODULE'),
('urllib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
'PYMODULE'),
('urllib.parse',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\parse.py',
'PYMODULE'),
('zipfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\zipfile.py',
'PYMODULE')])

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

View File

@ -0,0 +1,26 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named 'org.python' - imported by copy (optional)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
missing module named org - imported by pickle (optional)
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
missing module named resource - imported by posix (top-level)
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
missing module named _posixsubprocess - imported by subprocess (conditional)
missing module named fcntl - imported by subprocess (optional)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,328 @@
('E:\\SelfSpace\\pythontool\\npm_publish\\build\\NPM发布工具\\PYZ-00.pyz',
[('_compat_pickle',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_compat_pickle.py',
'PYMODULE'),
('_compression',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_compression.py',
'PYMODULE'),
('_py_abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_py_abc.py',
'PYMODULE'),
('_pydecimal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_pydecimal.py',
'PYMODULE'),
('_strptime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_strptime.py',
'PYMODULE'),
('_threading_local',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\_threading_local.py',
'PYMODULE'),
('argparse',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\argparse.py',
'PYMODULE'),
('ast',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ast.py',
'PYMODULE'),
('base64',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\base64.py',
'PYMODULE'),
('bisect',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bisect.py',
'PYMODULE'),
('bz2',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\bz2.py',
'PYMODULE'),
('calendar',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\calendar.py',
'PYMODULE'),
('contextlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\contextlib.py',
'PYMODULE'),
('contextvars',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\contextvars.py',
'PYMODULE'),
('copy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\copy.py',
'PYMODULE'),
('csv',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\csv.py',
'PYMODULE'),
('dataclasses',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\dataclasses.py',
'PYMODULE'),
('datetime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\datetime.py',
'PYMODULE'),
('decimal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\decimal.py',
'PYMODULE'),
('dis',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\dis.py',
'PYMODULE'),
('email',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\__init__.py',
'PYMODULE'),
('email._encoded_words',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_encoded_words.py',
'PYMODULE'),
('email._header_value_parser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_header_value_parser.py',
'PYMODULE'),
('email._parseaddr',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_parseaddr.py',
'PYMODULE'),
('email._policybase',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\_policybase.py',
'PYMODULE'),
('email.base64mime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\base64mime.py',
'PYMODULE'),
('email.charset',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\charset.py',
'PYMODULE'),
('email.contentmanager',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\contentmanager.py',
'PYMODULE'),
('email.encoders',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\encoders.py',
'PYMODULE'),
('email.errors',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\errors.py',
'PYMODULE'),
('email.feedparser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\feedparser.py',
'PYMODULE'),
('email.generator',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\generator.py',
'PYMODULE'),
('email.header',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\header.py',
'PYMODULE'),
('email.headerregistry',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\headerregistry.py',
'PYMODULE'),
('email.iterators',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\iterators.py',
'PYMODULE'),
('email.message',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\message.py',
'PYMODULE'),
('email.parser',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\parser.py',
'PYMODULE'),
('email.policy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\policy.py',
'PYMODULE'),
('email.quoprimime',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\quoprimime.py',
'PYMODULE'),
('email.utils',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\email\\utils.py',
'PYMODULE'),
('fnmatch',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\fnmatch.py',
'PYMODULE'),
('fractions',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\fractions.py',
'PYMODULE'),
('getopt',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\getopt.py',
'PYMODULE'),
('gettext',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gettext.py',
'PYMODULE'),
('gzip',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\gzip.py',
'PYMODULE'),
('hashlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\hashlib.py',
'PYMODULE'),
('importlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\__init__.py',
'PYMODULE'),
('importlib._abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_abc.py',
'PYMODULE'),
('importlib._bootstrap',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\_bootstrap_external.py',
'PYMODULE'),
('importlib.abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\abc.py',
'PYMODULE'),
('importlib.machinery',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\machinery.py',
'PYMODULE'),
('importlib.metadata',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\__init__.py',
'PYMODULE'),
('importlib.metadata._adapters',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_adapters.py',
'PYMODULE'),
('importlib.metadata._collections',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_collections.py',
'PYMODULE'),
('importlib.metadata._functools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_functools.py',
'PYMODULE'),
('importlib.metadata._itertools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_itertools.py',
'PYMODULE'),
('importlib.metadata._meta',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_meta.py',
'PYMODULE'),
('importlib.metadata._text',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\metadata\\_text.py',
'PYMODULE'),
('importlib.readers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\readers.py',
'PYMODULE'),
('importlib.resources',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\__init__.py',
'PYMODULE'),
('importlib.resources._adapters',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_adapters.py',
'PYMODULE'),
('importlib.resources._common',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_common.py',
'PYMODULE'),
('importlib.resources._itertools',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_itertools.py',
'PYMODULE'),
('importlib.resources._legacy',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\_legacy.py',
'PYMODULE'),
('importlib.resources.abc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\abc.py',
'PYMODULE'),
('importlib.resources.readers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\resources\\readers.py',
'PYMODULE'),
('importlib.util',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\importlib\\util.py',
'PYMODULE'),
('inspect',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\inspect.py',
'PYMODULE'),
('ipaddress',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\ipaddress.py',
'PYMODULE'),
('json',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\__init__.py',
'PYMODULE'),
('json.decoder',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\decoder.py',
'PYMODULE'),
('json.encoder',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\encoder.py',
'PYMODULE'),
('json.scanner',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\json\\scanner.py',
'PYMODULE'),
('logging',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\logging\\__init__.py',
'PYMODULE'),
('lzma',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\lzma.py',
'PYMODULE'),
('numbers',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\numbers.py',
'PYMODULE'),
('opcode',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\opcode.py',
'PYMODULE'),
('pathlib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pathlib.py',
'PYMODULE'),
('pickle',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pickle.py',
'PYMODULE'),
('pprint',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\pprint.py',
'PYMODULE'),
('py_compile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\py_compile.py',
'PYMODULE'),
('quopri',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\quopri.py',
'PYMODULE'),
('random',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\random.py',
'PYMODULE'),
('selectors',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\selectors.py',
'PYMODULE'),
('shutil',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\shutil.py',
'PYMODULE'),
('signal',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\signal.py',
'PYMODULE'),
('socket',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\socket.py',
'PYMODULE'),
('statistics',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\statistics.py',
'PYMODULE'),
('string',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\string.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\stringprep.py',
'PYMODULE'),
('subprocess',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\subprocess.py',
'PYMODULE'),
('tarfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tarfile.py',
'PYMODULE'),
('tempfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tempfile.py',
'PYMODULE'),
('textwrap',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\textwrap.py',
'PYMODULE'),
('threading',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\threading.py',
'PYMODULE'),
('tkinter',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\__init__.py',
'PYMODULE'),
('tkinter.commondialog',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\commondialog.py',
'PYMODULE'),
('tkinter.constants',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\constants.py',
'PYMODULE'),
('tkinter.messagebox',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\messagebox.py',
'PYMODULE'),
('tkinter.scrolledtext',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\scrolledtext.py',
'PYMODULE'),
('tkinter.ttk',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tkinter\\ttk.py',
'PYMODULE'),
('token',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\token.py',
'PYMODULE'),
('tokenize',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tokenize.py',
'PYMODULE'),
('tracemalloc',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\tracemalloc.py',
'PYMODULE'),
('typing',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\typing.py',
'PYMODULE'),
('urllib',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\__init__.py',
'PYMODULE'),
('urllib.parse',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\urllib\\parse.py',
'PYMODULE'),
('zipfile',
'C:\\Users\\hontbei\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\zipfile.py',
'PYMODULE')])

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

View File

@ -0,0 +1,26 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named 'org.python' - imported by copy (optional)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
missing module named org - imported by pickle (optional)
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
missing module named resource - imported by posix (top-level)
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (delayed, optional), subprocess (delayed, conditional, optional)
missing module named _posixsubprocess - imported by subprocess (conditional)
missing module named fcntl - imported by subprocess (optional)

File diff suppressed because it is too large Load Diff

BIN
npm_publish/dist/Excel查找工具.exe vendored Normal file

Binary file not shown.

BIN
npm_publish/dist/NPM发布工具.zip vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
{
"示例路径1": "C:/example/path1",
"示例路径2": "C:/example/path2",
"MeowmentDebugtool": "E:/WorkSpace/MeowMentDebugTool/Publish"
}

View File

@ -0,0 +1,3 @@
{
"last_selected": "MeowmentDebugtool"
}

Binary file not shown.

BIN
npm_publish/dist/消耗星星列表.exe vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,9 @@
{
"paths": {
"MeowmentDebugtool": "E:/WorkSpace/MeowMentDebugTool/Publish"
},
"servers": {
"局域网服务器": "192.168.1.120",
"老服务器byway": "https://npm.bywaystudios.com/"
}
}

View File

@ -0,0 +1,428 @@
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox
import json
import os
import tarfile
import shutil
import subprocess
from pathlib import Path
from datetime import datetime
import threading
class NPMPublishTool:
def __init__(self, root):
self.root = root
self.root.title("NPM 发布工具")
self.root.geometry("800x600")
# 配置文件路径
self.config_file = "npm_publish_config.json"
self.memory_file = "npm_publish_memory.json"
# 加载配置
self.load_config()
self.load_memory()
# 创建GUI
self.create_widgets()
# 恢复上次的选择
self.restore_last_selection()
def load_config(self):
"""加载路径配置"""
if os.path.exists(self.config_file):
try:
with open(self.config_file, 'r', encoding='utf-8') as f:
config = json.load(f)
self.paths_config = config.get('paths', {})
self.servers_config = config.get('servers', {})
except Exception as e:
self.paths_config = {}
self.servers_config = {}
self.log(f"加载配置文件失败: {e}")
else:
# 创建默认配置文件
self.paths_config = {
"示例路径1": "C:/example/path1",
"示例路径2": "C:/example/path2"
}
self.servers_config = {
"默认服务器": "https://npm.bywaystudios.com/",
"NPM官方": "https://registry.npmjs.org/"
}
self.save_config()
def save_config(self):
"""保存路径配置"""
try:
config = {
'paths': self.paths_config,
'servers': self.servers_config
}
with open(self.config_file, 'w', encoding='utf-8') as f:
json.dump(config, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存配置文件失败: {e}")
def load_memory(self):
"""加载记忆(上次选择)"""
if os.path.exists(self.memory_file):
try:
with open(self.memory_file, 'r', encoding='utf-8') as f:
self.memory = json.load(f)
except Exception as e:
self.memory = {}
else:
self.memory = {}
def save_memory(self):
"""保存记忆"""
try:
with open(self.memory_file, 'w', encoding='utf-8') as f:
json.dump(self.memory, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存记忆文件失败: {e}")
def create_widgets(self):
"""创建GUI组件"""
# 顶部框架 - 路径选择
top_frame = ttk.Frame(self.root, padding="10")
top_frame.pack(fill=tk.X)
ttk.Label(top_frame, text="选择路径:").grid(row=0, column=0, sticky=tk.W, padx=5)
self.path_var = tk.StringVar()
self.path_combo = ttk.Combobox(top_frame, textvariable=self.path_var,
values=list(self.paths_config.keys()),
state='readonly', width=40)
self.path_combo.grid(row=0, column=1, padx=5, sticky=tk.W)
# 显示实际路径
self.actual_path_label = ttk.Label(top_frame, text="实际路径: ", foreground="blue")
self.actual_path_label.grid(row=1, column=0, columnspan=2, sticky=tk.W, padx=5, pady=5)
# 服务器选择
ttk.Label(top_frame, text="选择服务器:").grid(row=2, column=0, sticky=tk.W, padx=5)
self.server_var = tk.StringVar()
self.server_combo = ttk.Combobox(top_frame, textvariable=self.server_var,
values=list(self.servers_config.keys()),
state='readonly', width=40)
self.server_combo.grid(row=2, column=1, padx=5, sticky=tk.W)
# 显示实际服务器地址
self.actual_server_label = ttk.Label(top_frame, text="服务器地址: ", foreground="green")
self.actual_server_label.grid(row=3, column=0, columnspan=2, sticky=tk.W, padx=5, pady=5)
# 绑定选择事件
self.path_combo.bind('<<ComboboxSelected>>', self.on_path_selected)
self.server_combo.bind('<<ComboboxSelected>>', self.on_server_selected)
# 按钮框架
button_frame = ttk.Frame(top_frame)
button_frame.grid(row=0, column=2, padx=5)
self.start_button = ttk.Button(button_frame, text="开始发布", command=self.start_publish)
self.start_button.pack(side=tk.LEFT, padx=2)
self.stop_button = ttk.Button(button_frame, text="停止", command=self.stop_publish, state=tk.DISABLED)
self.stop_button.pack(side=tk.LEFT, padx=2)
# 进度框架
progress_frame = ttk.Frame(self.root, padding="10")
progress_frame.pack(fill=tk.X)
ttk.Label(progress_frame, text="当前步骤:").pack(side=tk.LEFT, padx=5)
self.progress_label = ttk.Label(progress_frame, text="等待开始...", foreground="green")
self.progress_label.pack(side=tk.LEFT, padx=5)
self.progress_bar = ttk.Progressbar(progress_frame, mode='indeterminate')
self.progress_bar.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
# 日志框架
log_frame = ttk.LabelFrame(self.root, text="执行日志", padding="10")
log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
self.log_text = scrolledtext.ScrolledText(log_frame, wrap=tk.WORD, height=20)
self.log_text.pack(fill=tk.BOTH, expand=True)
# 状态栏
status_frame = ttk.Frame(self.root)
status_frame.pack(fill=tk.X, side=tk.BOTTOM)
self.status_label = ttk.Label(status_frame, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
self.status_label.pack(fill=tk.X, padx=5, pady=2)
# 运行标志
self.is_running = False
def on_path_selected(self, event):
"""路径选择事件"""
selected_key = self.path_var.get()
if selected_key in self.paths_config:
actual_path = self.paths_config[selected_key]
self.actual_path_label.config(text=f"实际路径: {actual_path}")
# 保存选择到记忆
self.memory['last_selected_path'] = selected_key
self.save_memory()
def on_server_selected(self, event):
"""服务器选择事件"""
selected_key = self.server_var.get()
if selected_key in self.servers_config:
actual_server = self.servers_config[selected_key]
self.actual_server_label.config(text=f"服务器地址: {actual_server}")
# 保存选择到记忆
self.memory['last_selected_server'] = selected_key
self.save_memory()
def restore_last_selection(self):
"""恢复上次的选择"""
# 恢复路径选择
if 'last_selected_path' in self.memory and self.memory['last_selected_path'] in self.paths_config:
self.path_var.set(self.memory['last_selected_path'])
self.on_path_selected(None)
elif 'last_selected' in self.memory and self.memory['last_selected'] in self.paths_config:
# 兼容旧版本的记忆字段
self.path_var.set(self.memory['last_selected'])
self.on_path_selected(None)
# 恢复服务器选择
if 'last_selected_server' in self.memory and self.memory['last_selected_server'] in self.servers_config:
self.server_var.set(self.memory['last_selected_server'])
self.on_server_selected(None)
elif self.servers_config:
# 如果没有记忆,选择第一个服务器
first_server = list(self.servers_config.keys())[0]
self.server_var.set(first_server)
self.on_server_selected(None)
def log(self, message):
"""添加日志"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
log_message = f"[{timestamp}] {message}\n"
self.log_text.insert(tk.END, log_message)
self.log_text.see(tk.END)
self.root.update()
def update_status(self, message):
"""更新状态栏"""
self.status_label.config(text=message)
self.root.update()
def update_progress(self, step):
"""更新进度标签"""
self.progress_label.config(text=step)
self.root.update()
def start_publish(self):
"""开始发布流程"""
if not self.path_var.get():
messagebox.showwarning("警告", "请先选择一个路径!")
return
if not self.server_var.get():
messagebox.showwarning("警告", "请先选择一个服务器!")
return
if self.is_running:
messagebox.showwarning("警告", "任务正在运行中!")
return
# 在新线程中运行
self.is_running = True
self.start_button.config(state=tk.DISABLED)
self.stop_button.config(state=tk.NORMAL)
thread = threading.Thread(target=self.publish_workflow, daemon=True)
thread.start()
def stop_publish(self):
"""停止发布流程"""
self.is_running = False
self.log("⚠️ 用户请求停止...")
def publish_workflow(self):
"""发布工作流程"""
try:
self.progress_bar.start()
# 步骤1: 获取目标路径
self.update_progress("步骤 1/6: 获取目标路径")
selected_key = self.path_var.get()
target_path = self.paths_config[selected_key]
self.log(f"✓ 目标路径: {target_path}")
if not os.path.exists(target_path):
raise Exception(f"路径不存在: {target_path}")
if not self.is_running:
return
# 步骤2: 查找最新的tgz文件
self.update_progress("步骤 2/6: 查找最新的tgz文件")
self.log("正在搜索最新的.tgz文件...")
tgz_files = list(Path(target_path).glob("*.tgz"))
if not tgz_files:
raise Exception(f"{target_path} 中未找到.tgz文件")
# 按修改时间排序,获取最新的
latest_tgz = max(tgz_files, key=lambda p: p.stat().st_mtime)
self.log(f"✓ 找到最新的tgz文件: {latest_tgz.name}")
self.log(f" 文件大小: {latest_tgz.stat().st_size / 1024:.2f} KB")
self.log(f" 修改时间: {datetime.fromtimestamp(latest_tgz.stat().st_mtime).strftime('%Y-%m-%d %H:%M:%S')}")
if not self.is_running:
return
# 步骤3: 解压tgz文件
self.update_progress("步骤 3/6: 解压tgz文件")
self.log(f"正在解压: {latest_tgz.name}")
extract_path = Path(target_path)
with tarfile.open(latest_tgz, 'r:gz') as tar:
tar.extractall(path=extract_path)
# 获取解压后的文件夹名称
members = tar.getmembers()
if members:
extracted_folder = members[0].name.split('/')[0]
else:
raise Exception("tgz文件为空")
extracted_folder_path = extract_path / extracted_folder
self.log(f"✓ 解压完成: {extracted_folder}")
if not self.is_running:
# 清理解压的文件夹
if extracted_folder_path.exists():
shutil.rmtree(extracted_folder_path)
return
# 步骤4: 检查package.json
self.update_progress("步骤 4/5: 检查package.json")
package_json = extracted_folder_path / "package.json"
if not package_json.exists():
raise Exception(f"未找到package.json文件: {package_json}")
self.log(f"✓ 找到package.json文件")
# 读取package.json获取包信息
try:
with open(package_json, 'r', encoding='utf-8') as f:
pkg_info = json.load(f)
pkg_name = pkg_info.get('name', 'unknown')
pkg_version = pkg_info.get('version', 'unknown')
self.log(f" 包名: {pkg_name}")
self.log(f" 版本: {pkg_version}")
except:
pass
if not self.is_running:
# 清理解压的文件夹
if extracted_folder_path.exists():
shutil.rmtree(extracted_folder_path)
return
# 步骤5: 执行npm publish
self.update_progress("步骤 5/5: 执行npm publish")
self.log("正在执行npm publish命令...")
# 获取选中的服务器地址
selected_server_key = self.server_var.get()
registry_url = self.servers_config[selected_server_key]
# 检查工作目录是否存在
if not os.path.exists(extracted_folder_path):
raise Exception(f"工作目录不存在: {extracted_folder_path}")
self.log(f"命令: npm publish --registry {registry_url}")
self.log(f"工作目录: {extracted_folder_path}")
# 使用shell=True直接执行npm命令这样可以使用系统PATH中的npm
process = subprocess.Popen(
f'npm publish --registry {registry_url}',
cwd=str(extracted_folder_path),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding='gbk',
errors='replace',
shell=True
)
# 实时输出
while True:
if not self.is_running:
process.terminate()
break
output = process.stdout.readline()
if output:
self.log(f" {output.strip()}")
error = process.stderr.readline()
if error:
self.log(f" [错误] {error.strip()}")
if output == '' and error == '' and process.poll() is not None:
break
return_code = process.returncode
if return_code == 0:
self.log("✓ npm publish 执行成功!")
self.update_status("发布成功!")
else:
self.log(f"⚠️ npm publish 执行失败,返回码: {return_code}")
self.update_status(f"发布失败,返回码: {return_code}")
# 步骤6: 清理解压的文件夹
self.update_progress("清理临时文件...")
self.log("正在删除解压的文件夹...")
if extracted_folder_path.exists():
shutil.rmtree(extracted_folder_path)
self.log(f"✓ 已删除: {extracted_folder}")
self.log("=" * 50)
self.log("✓ 所有步骤完成!")
self.update_progress("完成")
if return_code == 0:
messagebox.showinfo("成功", "NPM包发布成功")
else:
messagebox.showwarning("完成", "流程执行完成,但发布可能失败,请查看日志。")
except Exception as e:
self.log(f"❌ 错误: {str(e)}")
self.update_status(f"错误: {str(e)}")
self.update_progress("失败")
messagebox.showerror("错误", str(e))
# 尝试清理
try:
if 'extracted_folder_path' in locals() and extracted_folder_path.exists():
shutil.rmtree(extracted_folder_path)
self.log(f"✓ 已清理临时文件: {extracted_folder}")
except:
pass
finally:
self.progress_bar.stop()
self.is_running = False
self.start_button.config(state=tk.NORMAL)
self.stop_button.config(state=tk.DISABLED)
def main():
root = tk.Tk()
app = NPMPublishTool(root)
root.mainloop()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,168 @@
# NPM发布工具使用说明
## 功能说明
这是一个用于自动发布NPM包的GUI工具可以自动完成以下流程
1. 选择预设的路径
2. 查找最新的.tgz文件按修改时间
3. 解压tgz文件到当前文件夹
4. 检查解压文件夹中的package.json
5. 通过bat脚本执行npm publish命令
6. 自动清理临时文件和解压文件夹
## 配置说明
### 路径配置文件 (npm_publish_config.json)
首次运行时会自动创建配置文件,你可以手动编辑此文件来添加或修改预设路径:
```json
{
"开发环境": "E:/dev/npm-packages",
"生产环境": "D:/production/packages",
"测试环境": "C:/test/packages"
}
```
- **key**: 在下拉菜单中显示的名称
- **value**: 实际的文件路径
### 记忆文件 (npm_publish_memory.json)
工具会自动记住你上次选择的路径,下次打开时会自动恢复。
## 使用步骤
1. **启动工具**
- 直接双击运行 `NPM发布工具.exe`
- 或使用Python: `python npm_publish_gui.py`
2. **选择路径**
- 从下拉菜单中选择一个预设路径
- 工具会显示实际路径供确认
3. **开始发布**
- 点击"开始发布"按钮
- 工具会自动执行所有步骤
4. **查看进度**
- 顶部显示当前执行的步骤
- 进度条显示任务正在运行
- 日志窗口显示详细的执行过程
5. **停止任务**(可选)
- 如需中断任务,点击"停止"按钮
## 执行流程
### 步骤1: 获取目标路径
- 根据选择的key获取对应的文件路径
- 验证路径是否存在
### 步骤2: 查找最新的tgz文件
- 在目标路径下搜索所有.tgz文件
- 按修改时间排序,选择最新的文件
- 显示文件名、大小和修改时间
### 步骤3: 解压tgz文件
- 将tgz文件解压到当前文件夹
- 获取解压后的文件夹名称(通常为"package"
### 步骤4: 检查package.json
- 在解压的文件夹中直接查找package.json文件
- 读取并显示包名和版本号
### 步骤5: 执行npm publish
- 创建临时bat批处理文件
- 通过bat脚本在解压文件夹下执行npm publish命令
- 使用指定的registry: https://npm.bywaystudios.com/
- 实时显示命令输出信息(标记为[错误]的npm notice是正常输出
### 步骤6: 清理临时文件
- 删除临时bat批处理文件
- 删除解压出来的文件夹
- 释放磁盘空间
## 注意事项
1. **NPM环境**
- 确保系统已安装Node.js和npm
- 确保npm已登录到目标registry
- 可以先在命令行测试:`npm whoami --registry https://npm.bywaystudios.com/`
- **重要**如果npm是新安装的需要重启终端或重启电脑使环境变量生效
2. **路径格式**
- Windows系统建议使用正斜杠/)或双反斜杠(\\\\
- 例如:`C:/Users/xxx/packages` 或 `C:\\Users\\xxx\\packages`
3. **权限问题**
- 确保对目标路径有读写权限
- 确保对npm registry有发布权限
4. **错误处理**
- 如果发生错误,工具会自动清理临时文件
- 详细错误信息会显示在日志窗口中
5. **中断任务**
- 点击停止按钮后,工具会在当前步骤完成后停止
- 已解压的文件夹会被自动清理
6. **执行方式**
- 工具通过创建临时bat批处理文件来执行npm命令
- 这种方式确保完全继承系统环境变量,与手动执行效果完全一致
- 临时bat文件会在执行完成后自动删除
## 日志说明
日志中的符号含义:
- ✓ : 步骤成功完成
- ⚠️ : 警告信息
- ❌ : 错误信息
- [时间戳] : 每条日志的记录时间
- [错误] : 这个标签下的npm notice信息通常是正常输出不是真正的错误
## 常见问题
### Q: 提示找不到.tgz文件
A: 请检查选择的路径是否正确,确保该路径下有.tgz文件。
### Q: npm publish失败
A: 检查以下几点:
- npm是否已登录到目标registry
- 包名和版本是否符合规范
- 是否有发布权限
- 网络连接是否正常
### Q: 如何添加新的路径?
A: 编辑npm_publish_config.json文件添加新的键值对格式如下
```json
{
"新路径名称": "实际路径"
}
```
### Q: 如何修改npm registry地址
A: 编辑npm_publish_gui.py文件在步骤5的bat_content中修改registry地址
```python
bat_content = f"""@echo off
cd /d "{extracted_folder_path}"
npm publish --registry https://your-registry.com/
"""
```
### Q: 看到[错误]标签但发布成功了?
A: npm将某些正常信息如npm notice输出到stderr工具会标记为[错误],但这些不是真正的错误。只要最后显示"✓ npm publish 执行成功"就说明发布成功了。
### Q: exe文件在哪里
A: 运行打包后的程序,可执行文件位于 `dist/NPM发布工具.exe`配置文件和记忆文件会在exe同目录下自动创建。
## 技术说明
- **Python版本**: 3.11+
- **主要依赖**: tkinterGUI、tarfile解压、subprocess命令执行
- **执行方式**: 通过bat批处理脚本执行npm命令确保环境变量完全继承
- **打包工具**: PyInstaller--onefile --windowed
## 技术支持
如有问题或建议,请查看日志文件获取详细信息。

View File

@ -0,0 +1,5 @@
{
"last_selected": "MeowmentDebugtool",
"last_selected_path": "MeowmentDebugtool",
"last_selected_server": "默认服务器"
}

BIN
npm_publish/果汁.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""
排序 DecorateCost.xlsx AreaId (可选再按 SortId, Id)
特点:
1. 自动识别并删除第二行中文说明表头(例如出现 '区域Id','标题' )
2. 默认排序列顺序: AreaId, SortId, Id (仅当这些列存在)
3. 根据输出文件扩展名决定格式: .xlsx 输出 Excel, .csv 输出 CSV
4. 支持通过 --columns 自定义多级排序列
5. 保留原始列顺序仅重新排序行
用法示例 (PowerShell):
python .\sort_decoratecost_by_areaid.py \
--input DecorateCost.xlsx \
--output DecorateCost_sorted.xlsx
自定义排序列:
python .\sort_decoratecost_by_areaid.py --columns AreaId SortId Id
输出 CSV:
python .\sort_decoratecost_by_areaid.py --output DecorateCost_sorted.csv
如果环境未安装 pandas:
pip install pandas openpyxl
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
from typing import List
try:
import pandas as pd # type: ignore
except ImportError as e:
print("[错误] 需要安装 pandas 包: pip install pandas openpyxl", file=sys.stderr)
raise
CHINESE_HINTS = {"区域Id", "排序Id", "消耗资源数量", "标题", "图标", "位置", "行为", "交互动画", "对应按钮", "建造效果", "闪光效果", "原始大小/装饰特效位置", "装饰图标位置", "跳过逐步", "宠物经验"}
DEFAULT_SORT_ORDER = ["AreaId", "SortId", "Id"]
def detect_and_drop_second_header(df: pd.DataFrame) -> pd.DataFrame:
"""检测并删除可能的中文第二行表头。
逻辑: 如果第一行所有值中至少有一项与 CHINESE_HINTS 匹配超过 3 , 认为它是说明行, 删除
也兼容某些导出情况下第一行是英文列标题, 第二行是中文列标题我们只删除与 hints 匹配行
"""
if df.empty:
return df
# 检查前两行
rows_to_drop = []
check_rows = df.head(2).index.tolist()
for idx in check_rows:
row = df.loc[idx]
matches = sum(str(v) in CHINESE_HINTS for v in row.values)
# 行里出现的中文提示越多, 越可能是说明行
if matches >= 3:
rows_to_drop.append(idx)
if rows_to_drop:
df = df.drop(rows_to_drop).reset_index(drop=True)
return df
def parse_args(argv: List[str]) -> argparse.Namespace:
p = argparse.ArgumentParser(description="按指定列对 DecorateCost.xlsx 排序")
p.add_argument("--input", default="DecorateCost.xlsx", help="输入 Excel 文件路径")
p.add_argument("--sheet", default=0, help="工作表名称或序号 (默认第一个)" )
p.add_argument("--output", default="DecorateCost_sorted.xlsx", help="输出文件路径 (.xlsx 或 .csv)")
p.add_argument("--columns", nargs="*", help="自定义排序列 (默认 AreaId SortId Id)")
p.add_argument("--ascending", nargs="*", choices=["true","false"], help="对应排序列的升降序 true/false (长度与列数匹配)" )
p.add_argument("--keep-second-header", action="store_true", help="不尝试删除第二行中文说明表头")
return p.parse_args(argv)
def main(argv: List[str]) -> int:
args = parse_args(argv)
in_path = Path(args.input)
if not in_path.exists():
print(f"[错误] 输入文件不存在: {in_path}", file=sys.stderr)
return 2
# 读取
try:
df = pd.read_excel(in_path, sheet_name=args.sheet, header=0)
except Exception as e:
print(f"[错误] 读取 Excel 失败: {e}", file=sys.stderr)
return 3
original_columns = list(df.columns)
if not args.keep_second_header:
df = detect_and_drop_second_header(df)
# 确定排序列
sort_columns = args.columns if args.columns else [c for c in DEFAULT_SORT_ORDER if c in df.columns]
if not sort_columns:
print("[警告] 未找到任何默认排序列, 将不进行排序。")
sorted_df = df
else:
# 升降序解析
if args.ascending:
if len(args.ascending) != len(sort_columns):
print("[错误] --ascending 长度与排序列数量不符", file=sys.stderr)
return 4
ascending = [a.lower() == "true" for a in args.ascending]
else:
ascending = [True] * len(sort_columns)
missing = [c for c in sort_columns if c not in df.columns]
if missing:
print(f"[错误] 下列排序列在数据中缺失: {missing}", file=sys.stderr)
return 5
sorted_df = df.sort_values(by=sort_columns, ascending=ascending, kind="mergesort")
# 保留原始列顺序
sorted_df = sorted_df[original_columns]
out_path = Path(args.output)
try:
if out_path.suffix.lower() == ".csv":
sorted_df.to_csv(out_path, index=False, encoding="utf-8-sig")
else:
# 默认写 Excel
sorted_df.to_excel(out_path, index=False)
except Exception as e:
print(f"[错误] 写出文件失败: {e}", file=sys.stderr)
return 6
print(f"[完成] 已排序并写出到: {out_path}")
print(f"[信息] 行数: {len(sorted_df)} 列数: {len(sorted_df.columns)} 排序列: {sort_columns if sort_columns else ''}")
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))

33
translate.py Normal file
View File

@ -0,0 +1,33 @@
import pandas as pd
from googletrans import Translator
# 输入输出路径
input_file = "de.csv" # 你上传的德语语言文件
output_file = "zh.csv" # 翻译后的中文语言文件
# 读取 csv逗号分隔
df = pd.read_csv(input_file, header=None)
# 初始化翻译器
translator = Translator()
# 翻译第三列
translated = []
for text in df[2]:
if pd.isna(text): # 跳过空值
translated.append("")
else:
try:
result = translator.translate(str(text), src="de", dest="zh-cn")
translated.append(result.text)
except Exception as e:
print(f"翻译失败: {text} -> {e}")
translated.append(text)
# 替换第三列
df[2] = translated
# 保存
df.to_csv(output_file, index=False, header=False, encoding="utf-8")
print(f"翻译完成,保存为 {output_file}")

374
wav_to_mp3_gui.py Normal file
View File

@ -0,0 +1,374 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WAV转MP3批量转换器 - GUI版本
依赖: pydub (pip install pydub) + ffmpeg 可执行文件 (需自行下载放入路径)
"""
import os
import sys
import threading
import datetime
from pathlib import Path
from tkinter import *
from tkinter import ttk, filedialog, messagebox
from tkinter.scrolledtext import ScrolledText
try:
from pydub import AudioSegment
except ImportError:
AudioSegment = None
class WAVtoMP3ConverterGUI:
def __init__(self, root):
self.root = root
self.root.title("WAV转MP3转换器 v1.0")
self.root.geometry("850x620")
self.root.resizable(True, True)
# 变量
self.input_path = StringVar()
self.output_path = StringVar()
self.conversion_mode = StringVar(value="folder") # folder / file
self.delete_original = BooleanVar(value=False)
self.recursive = BooleanVar(value=True)
self.is_converting = False
self.bitrate = StringVar(value="192k") # 默认192kbps
self.ffmpeg_path = StringVar()
self.use_ffmpeg_custom = BooleanVar(value=False)
# 统计
self.total_files = 0
self.converted_files = 0
self.failed_files = 0
self.create_widgets()
def create_widgets(self):
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(N, S, W, E))
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
for i in range(0, 8):
main_frame.rowconfigure(i, weight=0)
main_frame.rowconfigure(7, weight=1)
main_frame.columnconfigure(1, weight=1)
title_label = ttk.Label(main_frame, text="🎵 WAV转MP3批量转换器", font=("Arial", 16, "bold"))
title_label.grid(row=0, column=0, columnspan=4, pady=(0, 15))
# 模式
mode_frame = ttk.LabelFrame(main_frame, text="转换模式", padding="8")
mode_frame.grid(row=1, column=0, columnspan=4, sticky=(W, E), pady=(0, 10))
ttk.Radiobutton(mode_frame, text="📁 文件夹批量", variable=self.conversion_mode, value="folder", command=self.on_mode_change).grid(row=0, column=0, sticky=W)
ttk.Radiobutton(mode_frame, text="📄 单文件", variable=self.conversion_mode, value="file", command=self.on_mode_change).grid(row=0, column=1, sticky=W)
# 输入
input_frame = ttk.LabelFrame(main_frame, text="输入路径", padding="8")
input_frame.grid(row=2, column=0, columnspan=4, sticky=(W, E), pady=(0, 10))
input_frame.columnconfigure(1, weight=1)
ttk.Label(input_frame, text="输入:").grid(row=0, column=0, sticky=W)
self.input_entry = ttk.Entry(input_frame, textvariable=self.input_path)
self.input_entry.grid(row=0, column=1, sticky=(W, E), padx=(4, 4))
self.input_browse_btn = ttk.Button(input_frame, text="浏览...", command=self.browse_input)
self.input_browse_btn.grid(row=0, column=2)
# 输出
output_frame = ttk.LabelFrame(main_frame, text="输出路径(可选)", padding="8")
output_frame.grid(row=3, column=0, columnspan=4, sticky=(W, E), pady=(0, 10))
output_frame.columnconfigure(1, weight=1)
ttk.Label(output_frame, text="输出:").grid(row=0, column=0, sticky=W)
ttk.Entry(output_frame, textvariable=self.output_path).grid(row=0, column=1, sticky=(W, E), padx=(4,4))
self.output_browse_btn = ttk.Button(output_frame, text="浏览...", command=self.browse_output)
self.output_browse_btn.grid(row=0, column=2)
ttk.Label(output_frame, text="💡 留空则MP3生成在原WAV旁边", foreground="gray").grid(row=1, column=0, columnspan=3, sticky=W, pady=(4,0))
# FFmpeg设置
ffmpeg_frame = ttk.LabelFrame(main_frame, text="FFmpeg设置", padding="8")
ffmpeg_frame.grid(row=4, column=0, columnspan=4, sticky=(W,E), pady=(0,10))
ffmpeg_frame.columnconfigure(2, weight=1)
ttk.Checkbutton(ffmpeg_frame, text="使用自定义ffmpeg路径", variable=self.use_ffmpeg_custom, command=self.on_ffmpeg_toggle).grid(row=0, column=0, sticky=W)
self.ffmpeg_entry = ttk.Entry(ffmpeg_frame, textvariable=self.ffmpeg_path, state='disabled')
self.ffmpeg_entry.grid(row=0, column=1, sticky=(W,E), padx=(4,4))
self.ffmpeg_btn = ttk.Button(ffmpeg_frame, text="选择ffmpeg.exe", command=self.browse_ffmpeg, state=DISABLED)
self.ffmpeg_btn.grid(row=0, column=2, sticky=W)
ttk.Label(ffmpeg_frame, text="⚠️ 需安装ffmpeg未找到时会尝试系统PATH", foreground="gray").grid(row=1, column=0, columnspan=4, sticky=W)
# 选项
options_frame = ttk.LabelFrame(main_frame, text="转换选项", padding="8")
options_frame.grid(row=5, column=0, columnspan=4, sticky=(W,E), pady=(0,10))
ttk.Checkbutton(options_frame, text="🗑️ 转换后删除原WAV", variable=self.delete_original).grid(row=0, column=0, sticky=W)
self.recursive_check = ttk.Checkbutton(options_frame, text="📂 递归子文件夹", variable=self.recursive)
self.recursive_check.grid(row=0, column=1, sticky=W)
ttk.Label(options_frame, text="比特率:").grid(row=1, column=0, sticky=E, pady=(6,0))
bitrate_combo = ttk.Combobox(options_frame, textvariable=self.bitrate, width=10, values=["128k","160k","192k","256k","320k"])
bitrate_combo.grid(row=1, column=1, sticky=W, pady=(6,0))
bitrate_combo.state(["!disabled", "readonly"])
# 控制按钮
button_frame = ttk.Frame(main_frame)
button_frame.grid(row=6, column=0, columnspan=4, pady=12)
self.start_btn = ttk.Button(button_frame, text="🚀 开始转换", command=self.start_conversion, style="Accent.TButton")
self.start_btn.pack(side=LEFT, padx=(0,10))
self.stop_btn = ttk.Button(button_frame, text="⏹️ 停止", command=self.stop_conversion, state=DISABLED)
self.stop_btn.pack(side=LEFT, padx=(0,10))
ttk.Button(button_frame, text="🗂️ 打开输出文件夹", command=self.open_output_folder).pack(side=LEFT)
# 进度
progress_frame = ttk.Frame(main_frame)
progress_frame.grid(row=7, column=0, columnspan=4, sticky=(W,E), pady=(0,10))
progress_frame.columnconfigure(0, weight=1)
self.progress_var = DoubleVar(value=0)
self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, maximum=100)
self.progress_bar.grid(row=0, column=0, sticky=(W,E), padx=(0,5))
self.progress_label = ttk.Label(progress_frame, text="准备就绪")
self.progress_label.grid(row=0, column=1)
# 日志
log_frame = ttk.LabelFrame(main_frame, text="转换日志", padding="6")
log_frame.grid(row=8, column=0, columnspan=4, sticky=(N,S,W,E))
log_frame.columnconfigure(0, weight=1)
log_frame.rowconfigure(0, weight=1)
self.log_text = ScrolledText(log_frame, height=14, wrap=WORD)
self.log_text.grid(row=0, column=0, sticky=(N,S,W,E))
self.on_mode_change()
def on_mode_change(self):
if self.conversion_mode.get() == 'file':
self.recursive_check.configure(state=DISABLED)
self.input_browse_btn.configure(text="选择文件...")
self.output_browse_btn.configure(text="保存为...")
else:
self.recursive_check.configure(state=NORMAL)
self.input_browse_btn.configure(text="选择文件夹...")
self.output_browse_btn.configure(text="选择文件夹...")
def on_ffmpeg_toggle(self):
use_custom = self.use_ffmpeg_custom.get()
self.ffmpeg_btn.configure(state=NORMAL if use_custom else DISABLED)
try:
self.ffmpeg_entry.configure(state='normal' if use_custom else 'disabled')
except Exception:
pass
def browse_ffmpeg(self):
path = filedialog.askopenfilename(title="选择ffmpeg可执行文件", filetypes=[("可执行文件","*.exe"), ("所有文件","*.*")])
if path:
self.ffmpeg_path.set(path)
def browse_input(self):
if self.conversion_mode.get() == 'file':
file_path = filedialog.askopenfilename(title="选择WAV文件", filetypes=[("WAV文件","*.wav *.WAV"),("所有文件","*.*")])
if file_path:
self.input_path.set(file_path)
else:
folder_path = filedialog.askdirectory(title="选择包含WAV文件的文件夹")
if folder_path:
self.input_path.set(folder_path)
def browse_output(self):
if self.conversion_mode.get() == 'file':
file_path = filedialog.asksaveasfilename(title="保存MP3文件为", defaultextension=".mp3", filetypes=[("MP3文件","*.mp3"),("所有文件","*.*")])
if file_path:
self.output_path.set(file_path)
else:
folder_path = filedialog.askdirectory(title="选择输出文件夹")
if folder_path:
self.output_path.set(folder_path)
def log_message(self, msg):
ts = datetime.datetime.now().strftime("%H:%M:%S")
self.log_text.insert(END, f"[{ts}] {msg}\n")
self.log_text.see(END)
self.root.update_idletasks()
def update_progress(self, current, total, status=""):
if total > 0:
self.progress_var.set((current/total)*100)
self.progress_label.configure(text=status if status else f"{current}/{total}")
self.root.update_idletasks()
def ensure_ffmpeg(self):
if AudioSegment is None:
raise RuntimeError("未安装pydub请先 pip install pydub")
# pydub 默认在 PATH 寻找 ffmpeg/avconv
if self.use_ffmpeg_custom.get():
custom = self.ffmpeg_path.get().strip()
if not custom:
raise RuntimeError("已勾选自定义ffmpeg但未选择路径")
if not Path(custom).exists():
raise RuntimeError("自定义ffmpeg路径不存在")
from pydub.utils import which
# 临时修改环境
os.environ['FFMPEG_BINARY'] = custom
if which(custom) or Path(custom).exists():
return custom
raise RuntimeError("无法使用指定的ffmpeg路径")
else:
# 尝试检测
from pydub.utils import which
if which('ffmpeg') is None:
self.log_message("⚠️ 未在PATH中检测到ffmpeg可能会转换失败。")
return 'ffmpeg'
def convert_single(self, wav_file: Path, output_file: Path):
try:
audio = AudioSegment.from_wav(wav_file)
output_file.parent.mkdir(parents=True, exist_ok=True)
audio.export(str(output_file), format="mp3", bitrate=self.bitrate.get())
self.converted_files += 1
self.log_message(f"✅ 转换成功: {wav_file.name} -> {output_file.name}")
if self.delete_original.get():
try:
wav_file.unlink()
self.log_message(f"🗑️ 已删除原文件: {wav_file.name}")
except Exception as e:
self.log_message(f"⚠️ 删除原文件失败: {e}")
except Exception as e:
self.failed_files += 1
self.log_message(f"❌ 转换失败 {wav_file.name}: {e}")
def find_wav_files(self, folder: Path, recursive: bool):
patterns = ["*.wav", "*.WAV"]
files = []
if recursive:
for p in patterns:
files.extend(folder.rglob(p))
else:
for p in patterns:
files.extend(folder.glob(p))
return files
def conversion_worker(self):
try:
self.total_files = 0
self.converted_files = 0
self.failed_files = 0
input_val = self.input_path.get().strip()
output_val = self.output_path.get().strip()
if not input_val:
self.log_message("❌ 请输入/选择输入路径")
return
self.ensure_ffmpeg()
if self.conversion_mode.get() == 'file':
wav_path = Path(input_val)
if not wav_path.exists():
self.log_message("❌ 输入文件不存在")
return
self.total_files = 1
self.update_progress(0,1,"转换中...")
if output_val:
out_path = Path(output_val)
else:
out_path = wav_path.with_suffix('.mp3')
self.convert_single(wav_path, out_path)
self.update_progress(1,1,"完成")
else:
folder = Path(input_val)
if not folder.exists() or not folder.is_dir():
self.log_message("❌ 输入文件夹不存在")
return
self.log_message(f"📁 扫描文件夹: {folder}")
wav_files = self.find_wav_files(folder, self.recursive.get())
if not wav_files:
self.log_message("🔍 未找到WAV文件")
return
self.total_files = len(wav_files)
self.log_message(f"🔍 找到 {self.total_files} 个WAV文件")
for idx, wav_f in enumerate(wav_files, start=1):
if not self.is_converting:
break
if output_val:
rel = wav_f.relative_to(folder)
out_file = Path(output_val) / rel.with_suffix('.mp3')
else:
out_file = wav_f.with_suffix('.mp3')
self.update_progress(idx-1, self.total_files, f"转换中 {idx}/{self.total_files}")
self.convert_single(wav_f, out_file)
self.update_progress(self.total_files, self.total_files, "完成")
self.log_message("="*50)
self.log_message("🎯 转换摘要")
self.log_message(f"📊 总文件: {self.total_files}")
self.log_message(f"✅ 成功: {self.converted_files}")
self.log_message(f"❌ 失败: {self.failed_files}")
self.log_message("="*50)
if self.converted_files > 0:
messagebox.showinfo("完成", f"转换完成!\n成功: {self.converted_files}\n失败: {self.failed_files}")
except Exception as e:
self.log_message(f"❌ 转换过程出错: {e}")
messagebox.showerror("错误", f"转换过程出错: {e}")
finally:
self.is_converting = False
self.start_btn.configure(state=NORMAL)
self.stop_btn.configure(state=DISABLED)
def start_conversion(self):
if self.is_converting:
return
if AudioSegment is None:
messagebox.showerror("错误", "未安装pydub请先 pip install pydub")
return
if not self.input_path.get().strip():
messagebox.showerror("错误", "请选择输入路径")
return
# 清日志
self.log_text.delete(1.0, END)
self.is_converting = True
self.start_btn.configure(state=DISABLED)
self.stop_btn.configure(state=NORMAL)
threading.Thread(target=self.conversion_worker, daemon=True).start()
def stop_conversion(self):
if self.is_converting:
self.is_converting = False
self.log_message("⏹️ 用户停止转换")
self.start_btn.configure(state=NORMAL)
self.stop_btn.configure(state=DISABLED)
def open_output_folder(self):
out = self.output_path.get().strip()
if out and Path(out).exists():
os.startfile(out)
else:
inp = self.input_path.get().strip()
if inp:
p = Path(inp)
if p.exists():
target = p.parent if p.is_file() else p
os.startfile(str(target))
else:
messagebox.showwarning("警告", "路径不存在")
else:
messagebox.showwarning("警告", "没有有效路径")
def main():
root = Tk()
style = ttk.Style()
try:
style.theme_use('winnative')
except:
pass
app = WAVtoMP3ConverterGUI(root)
def on_closing():
if app.is_converting:
if messagebox.askokcancel("退出", "正在转换中,确定要退出吗?"):
app.is_converting = False
root.destroy()
else:
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
if __name__ == '__main__':
try:
main()
except Exception as e:
print(f"程序启动失败: {e}")
import traceback; traceback.print_exc()

View File

@ -0,0 +1,57 @@
# WAV转MP3批量转换器 使用说明
本工具提供简单易用的图形界面,一键批量将 WAV 音频转换为 MP3。
## 功能特性
- 支持单个文件或整个文件夹批量转换(可选递归子文件夹)
- 支持设置输出目录(留空则在原地生成 .mp3
- 可选比特率128k/160k/192k/256k/320k
- 支持自定义 ffmpeg 路径
- 转换后可选择自动删除原 WAV 文件
- 进度条与详细日志显示
## 环境依赖
- Python 3.8+
- pydub 库(已在项目虚拟环境自动安装)
- ffmpeg 可执行文件(必须,负责实际编码 MP3
提示pydub 依赖 ffmpegffmpeg 需您自行安装并确保能被系统找到。
## Windows 安装 ffmpeg
1. 前往 https://www.gyan.dev/ffmpeg/builds/ 下载 ffmpeg release 版本(例如 ffmpeg-6.x-essentials_build.zip
2. 解压后得到 `ffmpeg\bin\ffmpeg.exe`
3. 任选其一:
- 将 `ffmpeg\bin` 添加到系统 PATH 环境变量;或
- 启动本工具后勾选“使用自定义 ffmpeg 路径”,并手动选择 `ffmpeg.exe`
## 运行
在 VS Code 中直接运行 `wav_to_mp3_gui.py`,或在终端执行:
```powershell
E:/SelfSpace/pythontool/.venv/Scripts/python.exe e:/SelfSpace/pythontool/wav_to_mp3_gui.py
```
若未启用虚拟环境,请先在 VS Code 右下角选择对应 Python 解释器。
## 使用步骤
1. 选择“转换模式”:
- 文件夹批量:选择包含 WAV 的文件夹,可选“递归子文件夹”
- 单文件:选择一个 WAV 文件
2. 选择“输出路径”(可选):
- 留空MP3 与原 WAV 同目录
- 填写:所有输出放到该目录,保持相对路径结构
3. 选择比特率(默认 192k
4. 如需,勾选“使用自定义 ffmpeg 路径”并指定 `ffmpeg.exe`
5. 点击“开始转换”,等待进度完成
6. 可在“转换日志”查看详细信息
## 常见问题
- 提示“未安装 pydub”请执行 `pip install pydub`
- 提示“未找到 ffmpeg”
- 确认已安装 ffmpeg 并将其 `bin` 目录加入 PATH
- 在程序中勾选自定义路径并选择 `ffmpeg.exe`
- 转换失败:
- 可能 WAV 文件损坏或编码不支持,查看日志具体错误
## 许可证
仅供个人学习与使用。

View File

@ -0,0 +1,47 @@
import os
import re
# ✅ 设置目标文件夹路径
folder_path = r"H:\里番\你被轻轻地带绿帽子"
# 匹配 [8位数字] 格式
date_bracket_pattern = re.compile(r'^\[(\d{8})\]')
def clean_filename(filename):
# 1. 逐个去掉最前面的 [YYYYMMDD] 中括号(可以多个)
while True:
match = date_bracket_pattern.match(filename)
if match:
filename = filename[match.end():] # 去掉匹配到的部分
else:
break
# 2. 去掉最前的数字 + 分隔符(如 001_, 02-03 空格等)
filename = re.sub(r'^\d+[\s_-]*', '', filename)
return filename
def rename_files(folder_path):
for filename in os.listdir(folder_path):
old_path = os.path.join(folder_path, filename)
if not os.path.isfile(old_path):
continue # 跳过子文件夹
new_filename = clean_filename(filename)
if new_filename != filename:
new_path = os.path.join(folder_path, new_filename)
if os.path.exists(new_path):
print(f"⚠️ 已存在: {new_filename},跳过")
continue
os.rename(old_path, new_path)
print(f"✅ 重命名: {filename} -> {new_filename}")
if __name__ == "__main__":
if os.path.isdir(folder_path):
rename_files(folder_path)
else:
print("❌ 路径无效,请检查 folder_path 是否正确")

125
壁纸处理测试脚本.py Normal file
View File

@ -0,0 +1,125 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
壁纸资源处理脚本 - 测试版本
这个版本只会显示会进行的操作不会实际删除或解压文件
"""
import os
import re
from pathlib import Path
from typing import List
class WallpaperProcessorTest:
def __init__(self, base_dir: str):
self.base_dir = Path(base_dir)
self.supported_extensions = ['.zip', '.rar', '.7z']
def is_duplicate_archive(self, filename: str) -> bool:
pattern = r'-[a-zA-Z0-9]{8,}'
return bool(re.search(pattern, filename))
def get_archive_files_in_directory(self, directory: Path) -> List[Path]:
archive_files = []
try:
for file_path in directory.iterdir():
if file_path.is_file() and file_path.suffix.lower() in self.supported_extensions:
archive_files.append(file_path)
except PermissionError:
print(f"权限不足,无法访问目录: {directory}")
return archive_files
def group_archives_by_base_name(self, archive_files: List[Path]) -> dict:
groups = {}
for archive in archive_files:
base_name = archive.stem
clean_name = re.sub(r'-[a-zA-Z0-9]{8,}$', '', base_name)
if clean_name not in groups:
groups[clean_name] = []
groups[clean_name].append(archive)
return groups
def analyze_directory(self, directory: Path) -> None:
print(f"\n分析目录: {directory}")
archive_files = self.get_archive_files_in_directory(directory)
if not archive_files:
print(" - 未找到压缩文件")
return
print(f" - 找到 {len(archive_files)} 个压缩文件:")
for archive in archive_files:
status = "重复文件" if self.is_duplicate_archive(archive.name) else "原始文件"
print(f" {archive.name} ({status})")
groups = self.group_archives_by_base_name(archive_files)
print(" - 处理计划:")
for base_name, files in groups.items():
if len(files) == 1:
print(f" 保留: {files[0].name}")
print(f" 解压: {files[0].name} -> {directory}")
else:
original_file = None
duplicates = []
for file in files:
if self.is_duplicate_archive(file.name):
duplicates.append(file)
else:
original_file = file
if original_file is None:
original_file = files[0]
duplicates = files[1:]
print(f" 保留: {original_file.name}")
print(f" 解压: {original_file.name} -> {directory}")
for duplicate in duplicates:
print(f" 删除: {duplicate.name}")
def analyze_all_directories(self) -> None:
if not self.base_dir.exists():
print(f"错误: 目录不存在 {self.base_dir}")
return
print(f"开始分析壁纸资源目录: {self.base_dir}")
total_dirs = 0
dirs_with_archives = 0
for root, dirs, files in os.walk(self.base_dir):
current_dir = Path(root)
total_dirs += 1
archive_files = self.get_archive_files_in_directory(current_dir)
if archive_files:
dirs_with_archives += 1
self.analyze_directory(current_dir)
print(f"\n分析完成!")
print(f"总共扫描了 {total_dirs} 个目录")
print(f"其中 {dirs_with_archives} 个目录包含压缩文件")
def main():
wallpaper_dir = r"E:\ResourceDownload\kuake\wallpaper壁纸资源"
if not os.path.exists(wallpaper_dir):
print(f"错误: 目录不存在 {wallpaper_dir}")
print("这是测试版本,只会分析文件而不会进行实际操作")
return
processor = WallpaperProcessorTest(wallpaper_dir)
try:
processor.analyze_all_directories()
except KeyboardInterrupt:
print("\n用户中断操作")
except Exception as e:
print(f"分析过程中发生错误: {e}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,72 @@
# 壁纸资源处理脚本使用说明
## 功能描述
这个脚本用于处理壁纸资源文件夹,主要功能包括:
1. **递归遍历目录结构** - 遍历指定目录及其所有子目录
2. **检测重复压缩包** - 识别带有 `-*****` 后缀的重复压缩文件
3. **删除重复文件** - 自动删除重复的压缩包,保留原始文件
4. **自动解压** - 将唯一的压缩文件解压到当前文件夹
## 支持的压缩格式
- ZIP (.zip)
- RAR (.rar)
- 7Z (.7z)
## 重复文件识别规则
脚本会识别以下模式的重复文件:
- `手机桌面(动态)壁纸文件(点击保存)-fc42285b9454.zip` ← 会被删除
- `手机桌面(动态)壁纸文件(点击保存).zip` ← 会被保留
规则:文件名中包含 `-` 后跟8位或以上字母数字组合的文件会被视为重复文件。
## 使用方法
### 1. 直接运行
```bash
python 壁纸资源处理脚本.py
```
### 2. 修改目标目录
如果需要处理其他目录,修改脚本中的 `wallpaper_dir` 变量:
```python
wallpaper_dir = r"你的目录路径"
```
## 处理流程
1. 检查目标目录是否存在
2. 递归遍历所有子目录
3. 在每个包含压缩文件的目录中:
- 识别重复的压缩包
- 删除重复文件
- 解压保留的唯一压缩文件
## 注意事项
⚠️ **重要提醒**
- 脚本会永久删除重复的压缩文件,请确保在运行前备份重要数据
- 建议先在测试目录中验证脚本行为
- 解压后的文件会保存在与压缩包相同的目录中
## 依赖包
脚本需要以下Python包
- `rarfile` - 处理RAR文件
- `py7zr` - 处理7Z文件
- `zipfile` - 处理ZIP文件Python内置
## 示例输出
```
开始处理壁纸资源目录: E:\ResourceDownload\kuake\wallpaper壁纸资源
处理目录: E:\ResourceDownload\kuake\wallpaper壁纸资源\子目录1
删除重复文件: E:\ResourceDownload\kuake\wallpaper壁纸资源\子目录1\壁纸文件-fc42285b9454.zip
正在解压: E:\ResourceDownload\kuake\wallpaper壁纸资源\子目录1\壁纸文件.zip -> E:\ResourceDownload\kuake\wallpaper壁纸资源\子目录1
解压完成: E:\ResourceDownload\kuake\wallpaper壁纸资源\子目录1\壁纸文件.zip
处理完成!
```
## 错误处理
脚本包含完善的错误处理机制:
- 如果目录不存在,会显示错误信息
- 如果解压失败,会显示具体错误信息
- 支持 Ctrl+C 中断操作

253
壁纸资源处理脚本.py Normal file
View File

@ -0,0 +1,253 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
壁纸资源处理脚本
功能
1. 遍历指定目录的循环结构
2. 检查压缩包
3. 删除重复的压缩包带有-*****后缀的
4. 解压唯一的压缩文件到当前文件夹
"""
import os
import zipfile
import rarfile
import re
import shutil
from pathlib import Path
from typing import List, Tuple
class WallpaperProcessor:
def __init__(self, base_dir: str):
"""
初始化壁纸处理器
Args:
base_dir: 壁纸资源的基础目录
"""
self.base_dir = Path(base_dir)
self.supported_extensions = ['.zip', '.rar', '.7z']
def is_duplicate_archive(self, filename: str) -> bool:
"""
检查是否为重复的压缩包
重复压缩包特征文件名包含 -fc42285b9454 或类似的 -**** 模式
Args:
filename: 文件名
Returns:
bool: 是否为重复文件
"""
# 匹配模式:-后跟字母数字组合
pattern = r'-[a-zA-Z0-9]{8,}'
return bool(re.search(pattern, filename))
def get_archive_files_in_directory(self, directory: Path) -> List[Path]:
"""
获取目录中的所有压缩文件
Args:
directory: 目录路径
Returns:
List[Path]: 压缩文件列表
"""
archive_files = []
for file_path in directory.iterdir():
if file_path.is_file() and file_path.suffix.lower() in self.supported_extensions:
archive_files.append(file_path)
return archive_files
def group_archives_by_base_name(self, archive_files: List[Path]) -> dict:
"""
根据基础名称对压缩文件进行分组
Args:
archive_files: 压缩文件列表
Returns:
dict: 分组后的压缩文件字典
"""
groups = {}
for archive in archive_files:
# 移除扩展名和可能的重复标识符
base_name = archive.stem
# 移除-****模式的后缀
clean_name = re.sub(r'-[a-zA-Z0-9]{8,}$', '', base_name)
if clean_name not in groups:
groups[clean_name] = []
groups[clean_name].append(archive)
return groups
def remove_duplicate_archives(self, directory: Path) -> List[Path]:
"""
删除重复的压缩包保留原始文件
Args:
directory: 目录路径
Returns:
List[Path]: 保留的唯一压缩文件列表
"""
archive_files = self.get_archive_files_in_directory(directory)
if not archive_files:
return []
groups = self.group_archives_by_base_name(archive_files)
unique_archives = []
for base_name, files in groups.items():
if len(files) == 1:
# 只有一个文件,直接保留
unique_archives.append(files[0])
else:
# 多个文件,保留非重复的(不含-****模式的)
original_file = None
duplicates = []
for file in files:
if self.is_duplicate_archive(file.name):
duplicates.append(file)
else:
original_file = file
# 如果没有找到原始文件,保留第一个
if original_file is None:
original_file = files[0]
duplicates = files[1:]
# 删除重复文件
for duplicate in duplicates:
try:
print(f"删除重复文件: {duplicate}")
duplicate.unlink()
except Exception as e:
print(f"删除文件失败 {duplicate}: {e}")
unique_archives.append(original_file)
return unique_archives
def extract_archive(self, archive_path: Path, extract_to: Path) -> bool:
"""
解压缩文件支持中文文件名
Args:
archive_path: 压缩文件路径
extract_to: 解压目标路径
Returns:
bool: 解压是否成功
"""
try:
print(f"正在解压: {archive_path} -> {extract_to}")
if archive_path.suffix.lower() == '.zip':
# 尝试不同的编码方式解决中文乱码问题
encodings = ['utf-8', 'gbk', 'gb2312', 'cp437']
for encoding in encodings:
try:
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
# 检查文件名编码
for file_info in zip_ref.filelist:
try:
# 尝试用当前编码解码文件名
file_info.filename.encode('cp437').decode(encoding)
# 如果成功,设置正确的文件名
if encoding != 'utf-8':
file_info.filename = file_info.filename.encode('cp437').decode(encoding)
except (UnicodeDecodeError, UnicodeEncodeError):
continue
zip_ref.extractall(extract_to)
break
except Exception:
if encoding == encodings[-1]: # 如果所有编码都失败
# 使用默认方式解压
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
zip_ref.extractall(extract_to)
continue
elif archive_path.suffix.lower() == '.rar':
with rarfile.RarFile(archive_path, 'r') as rar_ref:
# RAR文件通常能正确处理中文
rar_ref.extractall(extract_to)
elif archive_path.suffix.lower() == '.7z':
# 需要安装 py7zr 库
import py7zr
with py7zr.SevenZipFile(archive_path, mode='r') as z:
z.extractall(extract_to)
print(f"解压完成: {archive_path}")
return True
except Exception as e:
print(f"解压失败 {archive_path}: {e}")
return False
def process_directory(self, directory: Path) -> None:
"""
处理单个目录
Args:
directory: 要处理的目录
"""
print(f"\n处理目录: {directory}")
# 删除重复的压缩包
unique_archives = self.remove_duplicate_archives(directory)
# 解压每个唯一的压缩文件
for archive in unique_archives:
self.extract_archive(archive, directory)
def process_all_directories(self) -> None:
"""
处理所有目录递归遍历
"""
if not self.base_dir.exists():
print(f"错误: 目录不存在 {self.base_dir}")
return
print(f"开始处理壁纸资源目录: {self.base_dir}")
# 递归遍历所有子目录
for root, dirs, files in os.walk(self.base_dir):
current_dir = Path(root)
# 检查当前目录是否包含压缩文件
archive_files = self.get_archive_files_in_directory(current_dir)
if archive_files:
self.process_directory(current_dir)
print("\n处理完成!")
def main():
"""主函数"""
# 壁纸资源目录
wallpaper_dir = r"E:\ResourceDownload\kuake\wallpaper壁纸资源"
# 检查目录是否存在
if not os.path.exists(wallpaper_dir):
print(f"错误: 目录不存在 {wallpaper_dir}")
return
# 创建处理器实例
processor = WallpaperProcessor(wallpaper_dir)
# 开始处理
try:
processor.process_all_directories()
except KeyboardInterrupt:
print("\n用户中断操作")
except Exception as e:
print(f"处理过程中发生错误: {e}")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,296 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
壁纸资源处理脚本 - 增强版解决中文乱码问题
功能
1. 遍历指定目录的循环结构
2. 检查压缩包
3. 删除重复的压缩包带有-*****后缀的
4. 解压唯一的压缩文件到当前文件夹支持中文文件名
"""
import os
import zipfile
import rarfile
import re
import shutil
from pathlib import Path
from typing import List, Tuple
class WallpaperProcessorEnhanced:
def __init__(self, base_dir: str):
"""
初始化壁纸处理器
Args:
base_dir: 壁纸资源的基础目录
"""
self.base_dir = Path(base_dir)
self.supported_extensions = ['.zip', '.rar', '.7z']
def is_duplicate_archive(self, filename: str) -> bool:
"""
检查是否为重复的压缩包
重复压缩包特征文件名包含 -fc42285b9454 或类似的 -**** 模式
Args:
filename: 文件名
Returns:
bool: 是否为重复文件
"""
# 匹配模式:-后跟字母数字组合
pattern = r'-[a-zA-Z0-9]{8,}'
return bool(re.search(pattern, filename))
def get_archive_files_in_directory(self, directory: Path) -> List[Path]:
"""
获取目录中的所有压缩文件
Args:
directory: 目录路径
Returns:
List[Path]: 压缩文件列表
"""
archive_files = []
for file_path in directory.iterdir():
if file_path.is_file() and file_path.suffix.lower() in self.supported_extensions:
archive_files.append(file_path)
return archive_files
def group_archives_by_base_name(self, archive_files: List[Path]) -> dict:
"""
根据基础名称对压缩文件进行分组
Args:
archive_files: 压缩文件列表
Returns:
dict: 分组后的压缩文件字典
"""
groups = {}
for archive in archive_files:
# 移除扩展名和可能的重复标识符
base_name = archive.stem
# 移除-****模式的后缀
clean_name = re.sub(r'-[a-zA-Z0-9]{8,}$', '', base_name)
if clean_name not in groups:
groups[clean_name] = []
groups[clean_name].append(archive)
return groups
def fix_zip_filename_encoding(self, zip_path: Path, extract_to: Path) -> bool:
"""
修复ZIP文件中文文件名编码问题
Args:
zip_path: ZIP文件路径
extract_to: 解压目标路径
Returns:
bool: 是否成功解压
"""
try:
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
for file_info in zip_ref.filelist:
# 获取原始文件名
filename = file_info.filename
# 尝试不同的编码方式
fixed_filename = None
encodings = ['utf-8', 'gbk', 'gb2312', 'big5', 'shift_jis']
for encoding in encodings:
try:
# 尝试将文件名从cp437编码转换为指定编码
fixed_filename = filename.encode('cp437').decode(encoding)
# 检查是否包含中文字符
if any('\u4e00' <= char <= '\u9fff' for char in fixed_filename):
break
except (UnicodeDecodeError, UnicodeEncodeError):
continue
# 如果没找到合适的编码,使用原文件名
if fixed_filename is None:
fixed_filename = filename
# 创建目标文件路径
target_path = extract_to / fixed_filename
target_path.parent.mkdir(parents=True, exist_ok=True)
# 如果是目录,跳过
if filename.endswith('/'):
target_path.mkdir(parents=True, exist_ok=True)
continue
# 解压文件
with zip_ref.open(file_info) as source, open(target_path, 'wb') as target:
target.write(source.read())
return True
except Exception as e:
print(f"使用增强解压方法失败: {e}")
return False
def extract_archive(self, archive_path: Path, extract_to: Path) -> bool:
"""
解压缩文件支持中文文件名
Args:
archive_path: 压缩文件路径
extract_to: 解压目标路径
Returns:
bool: 解压是否成功
"""
try:
print(f"正在解压: {archive_path} -> {extract_to}")
if archive_path.suffix.lower() == '.zip':
# 首先尝试标准方法
try:
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
zip_ref.extractall(extract_to)
print(f"解压完成: {archive_path}")
return True
except Exception:
print("标准解压方法失败,尝试修复中文编码...")
# 如果标准方法失败,使用增强方法
if self.fix_zip_filename_encoding(archive_path, extract_to):
print(f"解压完成(已修复中文编码): {archive_path}")
return True
else:
raise Exception("所有解压方法都失败")
elif archive_path.suffix.lower() == '.rar':
with rarfile.RarFile(archive_path, 'r') as rar_ref:
# RAR文件通常能正确处理中文
rar_ref.extractall(extract_to)
elif archive_path.suffix.lower() == '.7z':
# 需要安装 py7zr 库
import py7zr
with py7zr.SevenZipFile(archive_path, mode='r') as z:
z.extractall(extract_to)
print(f"解压完成: {archive_path}")
return True
except Exception as e:
print(f"解压失败 {archive_path}: {e}")
return False
def remove_duplicate_archives(self, directory: Path) -> List[Path]:
"""
删除重复的压缩包保留原始文件
Args:
directory: 目录路径
Returns:
List[Path]: 保留的唯一压缩文件列表
"""
archive_files = self.get_archive_files_in_directory(directory)
if not archive_files:
return []
groups = self.group_archives_by_base_name(archive_files)
unique_archives = []
for base_name, files in groups.items():
if len(files) == 1:
# 只有一个文件,直接保留
unique_archives.append(files[0])
else:
# 多个文件,保留非重复的(不含-****模式的)
original_file = None
duplicates = []
for file in files:
if self.is_duplicate_archive(file.name):
duplicates.append(file)
else:
original_file = file
# 如果没有找到原始文件,保留第一个
if original_file is None:
original_file = files[0]
duplicates = files[1:]
# 删除重复文件
for duplicate in duplicates:
try:
print(f"删除重复文件: {duplicate}")
duplicate.unlink()
except Exception as e:
print(f"删除文件失败 {duplicate}: {e}")
unique_archives.append(original_file)
return unique_archives
def process_directory(self, directory: Path) -> None:
"""
处理单个目录
Args:
directory: 要处理的目录
"""
print(f"\n处理目录: {directory}")
# 删除重复的压缩包
unique_archives = self.remove_duplicate_archives(directory)
# 解压每个唯一的压缩文件
for archive in unique_archives:
self.extract_archive(archive, directory)
def process_all_directories(self) -> None:
"""
处理所有目录递归遍历
"""
if not self.base_dir.exists():
print(f"错误: 目录不存在 {self.base_dir}")
return
print(f"开始处理壁纸资源目录: {self.base_dir}")
# 递归遍历所有子目录
for root, dirs, files in os.walk(self.base_dir):
current_dir = Path(root)
# 检查当前目录是否包含压缩文件
archive_files = self.get_archive_files_in_directory(current_dir)
if archive_files:
self.process_directory(current_dir)
print("\n处理完成!")
def main():
"""主函数"""
# 壁纸资源目录
wallpaper_dir = r"E:\ResourceDownload\kuake\wallpaper壁纸资源"
# 检查目录是否存在
if not os.path.exists(wallpaper_dir):
print(f"错误: 目录不存在 {wallpaper_dir}")
return
# 创建处理器实例
processor = WallpaperProcessorEnhanced(wallpaper_dir)
# 开始处理
try:
processor.process_all_directories()
except KeyboardInterrupt:
print("\n用户中断操作")
except Exception as e:
print(f"处理过程中发生错误: {e}")
if __name__ == "__main__":
main()

104
测试中文解压.py Normal file
View File

@ -0,0 +1,104 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试单个压缩文件的中文解压功能
"""
import os
import zipfile
from pathlib import Path
def test_single_archive(archive_path: str, extract_to: str):
"""
测试单个压缩文件的解压专门处理中文编码问题
"""
archive_path = Path(archive_path)
extract_to = Path(extract_to)
if not archive_path.exists():
print(f"文件不存在: {archive_path}")
return
# 确保解压目录存在
extract_to.mkdir(parents=True, exist_ok=True)
print(f"测试解压文件: {archive_path}")
print(f"解压到: {extract_to}")
try:
with zipfile.ZipFile(archive_path, 'r') as zip_ref:
print("\n压缩包内容:")
for file_info in zip_ref.filelist:
original_name = file_info.filename
print(f"原始文件名: {repr(original_name)}")
# 尝试不同编码
encodings = ['utf-8', 'gbk', 'gb2312', 'big5']
for encoding in encodings:
try:
fixed_name = original_name.encode('cp437').decode(encoding)
if any('\u4e00' <= char <= '\u9fff' for char in fixed_name):
print(f" {encoding} 编码: {fixed_name}")
else:
print(f" {encoding} 编码: {fixed_name} (无中文)")
except (UnicodeDecodeError, UnicodeEncodeError):
print(f" {encoding} 编码: 解码失败")
print("-" * 50)
# 使用增强方法解压
print("\n开始解压...")
for file_info in zip_ref.filelist:
filename = file_info.filename
# 尝试修复文件名
fixed_filename = filename
encodings = ['gbk', 'gb2312', 'utf-8', 'big5']
for encoding in encodings:
try:
test_name = filename.encode('cp437').decode(encoding)
if any('\u4e00' <= char <= '\u9fff' for char in test_name):
fixed_filename = test_name
print(f"使用 {encoding} 编码修复文件名: {fixed_filename}")
break
except (UnicodeDecodeError, UnicodeEncodeError):
continue
# 创建目标路径
target_path = extract_to / fixed_filename
target_path.parent.mkdir(parents=True, exist_ok=True)
# 如果是目录,跳过
if filename.endswith('/'):
continue
# 解压文件
with zip_ref.open(file_info) as source, open(target_path, 'wb') as target:
target.write(source.read())
print(f"解压完成: {target_path}")
print("\n解压完成!")
except Exception as e:
print(f"解压失败: {e}")
def main():
"""主函数"""
print("请输入要测试的压缩文件路径和解压目录:")
# 示例路径,你可以修改这些路径
archive_path = input("压缩文件路径: ").strip()
if not archive_path:
# 默认测试路径
archive_path = r"E:\ResourceDownload\kuake\wallpaper壁纸资源\2024年壁纸推荐手机版\2024年9月\24.9.21 修女篇\4K静态原图序号对应也可以直接作为壁纸使用\原图.zip"
extract_to = input("解压目录 (默认: ./test_extract): ").strip()
if not extract_to:
extract_to = "./test_extract"
test_single_archive(archive_path, extract_to)
if __name__ == "__main__":
main()

12
消耗星星列表.py Normal file
View File

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
def repeat_print():
string1 = "205 300 396 491 586"
numbers = string1.split()
for number in numbers:
for index in range(0,5):
print(number);
if __name__ == "__main__":
repeat_print()

38
消耗星星列表.spec Normal file
View File

@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['消耗星星列表_gui.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='消耗星星列表',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)

Some files were not shown because too many files have changed in this diff Show More