mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-01 21:07:01 +08:00
95 lines
3.1 KiB
Python
95 lines
3.1 KiB
Python
"""
|
||
字节容量的解析与显示基础能力。
|
||
"""
|
||
|
||
import bisect
|
||
import re
|
||
from typing import Union
|
||
|
||
|
||
def parse_size(text: Union[str, int, float]) -> int:
|
||
"""
|
||
将带二进制容量单位的文本转换为字节数。
|
||
|
||
:param text: 数字或容量文本,支持千位分隔符和 KB 至 PB 等单位
|
||
:return: 四舍五入后的字节数;空值或无法解析的数值文本返回 0
|
||
"""
|
||
if not text:
|
||
return 0
|
||
if not isinstance(text, str):
|
||
text = str(text)
|
||
if text.isdigit():
|
||
return int(text)
|
||
normalized = text.replace(",", "").replace(" ", "").upper()
|
||
size_text = re.sub(r"[KMGTPI]*B?", "", normalized, flags=re.IGNORECASE)
|
||
try:
|
||
size = float(size_text)
|
||
except ValueError:
|
||
return 0
|
||
if "PB" in normalized or "PIB" in normalized:
|
||
size *= 1024 ** 5
|
||
elif "TB" in normalized or "TIB" in normalized:
|
||
size *= 1024 ** 4
|
||
elif "GB" in normalized or "GIB" in normalized:
|
||
size *= 1024 ** 3
|
||
elif "MB" in normalized or "MIB" in normalized:
|
||
size *= 1024 ** 2
|
||
elif "KB" in normalized or "KIB" in normalized:
|
||
size *= 1024
|
||
return round(size)
|
||
|
||
|
||
def format_compact_size(size: Union[str, float, int], precision: int = 2) -> str:
|
||
"""
|
||
将字节数格式化为紧凑容量文本。
|
||
|
||
:param size: 字节数或已有单位的文本;None 返回空字符串
|
||
:param precision: 容量换算后保留的小数位数
|
||
:return: 小容量保留 B,大容量使用 K、M、G、T 等简写
|
||
"""
|
||
if size is None:
|
||
return ""
|
||
# 历史实现把 re.IGNORECASE 作为 count 位置参数传入;这里保留其最多替换两次、
|
||
# 且仅匹配大写单位的实际行为,避免旧插件在边缘输入上发生变化。
|
||
normalized = re.sub(r"\s|B|iB", "", str(size), count=re.IGNORECASE)
|
||
if normalized.replace(".", "").isdigit():
|
||
try:
|
||
numeric_size = float(normalized)
|
||
thresholds = [
|
||
(1024 - 1, "K"),
|
||
(1024 ** 2 - 1, "M"),
|
||
(1024 ** 3 - 1, "G"),
|
||
(1024 ** 4 - 1, "T"),
|
||
]
|
||
index = bisect.bisect_left(
|
||
[threshold for threshold, _unit in thresholds], numeric_size
|
||
) - 1
|
||
if index == -1:
|
||
return f"{numeric_size}B"
|
||
threshold, unit = thresholds[index]
|
||
return f"{round(numeric_size / (threshold + 1), precision)}{unit}"
|
||
except ValueError:
|
||
return ""
|
||
if re.findall(r"[KMGTP]", normalized, re.IGNORECASE):
|
||
return normalized
|
||
return f"{normalized}B"
|
||
|
||
|
||
def format_size(size_bytes: int) -> str:
|
||
"""
|
||
将字节数转换为带空格和完整单位的人类可读格式。
|
||
"""
|
||
if not size_bytes:
|
||
return "0 B"
|
||
|
||
units = ["B", "KB", "MB", "GB", "TB", "PB"]
|
||
size = float(size_bytes)
|
||
unit_index = 0
|
||
while size >= 1024 and unit_index < len(units) - 1:
|
||
size /= 1024
|
||
unit_index += 1
|
||
|
||
if unit_index == 0:
|
||
return f"{int(size)} {units[unit_index]}"
|
||
return f"{size:.2f} {units[unit_index]}"
|