升级 PaddleOCR 至 3.4.0,移除 PP-OCRv4 模型
- PaddleOCR 2.10.0 升级至 3.4.0,使用新的 TextDetection API 替代旧版 TextDetector - V5 模型替换为 PaddleX 格式(inference.pdiparams + inference.yml) - 移除 PP-OCRv4 模型(backend/models/V4),仅保留 PP-OCRv5 - 字幕检测选项重命名为"快速"和"精准" - 清理 requirements.txt,移除 11 个未使用的依赖,补充缺失的依赖 - 更新设计素材 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
d023ca775c
commit
70e669e9d4
+1
-1
@@ -52,7 +52,7 @@ class Config(QConfig):
|
|||||||
# 【设置inpaint算法】
|
# 【设置inpaint算法】
|
||||||
inpaintMode = OptionsConfigItem("Main", "InpaintMode", InpaintMode.STTN_AUTO, OptionsValidator(InpaintMode), EnumSerializer(InpaintMode))
|
inpaintMode = OptionsConfigItem("Main", "InpaintMode", InpaintMode.STTN_AUTO, OptionsValidator(InpaintMode), EnumSerializer(InpaintMode))
|
||||||
|
|
||||||
subtitleDetectMode = OptionsConfigItem("Main", "SubtitleDetectMode", SubtitleDetectMode.PP_OCRv4_SERVER, OptionsValidator(SubtitleDetectMode), EnumSerializer(SubtitleDetectMode))
|
subtitleDetectMode = OptionsConfigItem("Main", "SubtitleDetectMode", SubtitleDetectMode.PP_OCRv5_SERVER, OptionsValidator(SubtitleDetectMode), EnumSerializer(SubtitleDetectMode))
|
||||||
|
|
||||||
# 【设置像素点偏差】
|
# 【设置像素点偏差】
|
||||||
# 用于判断是不是非字幕区域(一般认为字幕文本框的长度是要大于宽度的,如果字幕框的高大于宽,且大于的幅度超过指定像素点大小,则认为是错误检测)
|
# 用于判断是不是非字幕区域(一般认为字幕文本框的长度是要大于宽度的,如果字幕框的高大于宽,且大于的幅度超过指定像素点大小,则认为是错误检测)
|
||||||
|
|||||||
Regular → Executable
@@ -1,4 +0,0 @@
|
|||||||
filename,filesize,encoding,header␍
|
|
||||||
inference_1.onnx,50000000,,␍
|
|
||||||
inference_2.onnx,50000000,,␍
|
|
||||||
inference_3.onnx,13443410,,␍
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,111 @@
|
|||||||
|
{
|
||||||
|
"Global": {
|
||||||
|
"model_name": "PP-OCRv5_server_det"
|
||||||
|
},
|
||||||
|
"Hpi": {
|
||||||
|
"backend_configs": {
|
||||||
|
"paddle_infer": {
|
||||||
|
"trt_dynamic_shapes": {
|
||||||
|
"x": [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
32,
|
||||||
|
32
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
736,
|
||||||
|
736
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
4000,
|
||||||
|
4000
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tensorrt": {
|
||||||
|
"dynamic_shapes": {
|
||||||
|
"x": [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
32,
|
||||||
|
32
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
736,
|
||||||
|
736
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
4000,
|
||||||
|
4000
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PreProcess": {
|
||||||
|
"transform_ops": [
|
||||||
|
{
|
||||||
|
"DecodeImage": {
|
||||||
|
"channel_first": false,
|
||||||
|
"img_mode": "BGR"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DetLabelEncode": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DetResizeForTest": {
|
||||||
|
"resize_long": 960
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NormalizeImage": {
|
||||||
|
"mean": [
|
||||||
|
0.485,
|
||||||
|
0.456,
|
||||||
|
0.406
|
||||||
|
],
|
||||||
|
"order": "hwc",
|
||||||
|
"scale": "1./255.",
|
||||||
|
"std": [
|
||||||
|
0.229,
|
||||||
|
0.224,
|
||||||
|
0.225
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ToCHWImage": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"KeepKeys": {
|
||||||
|
"keep_keys": [
|
||||||
|
"image",
|
||||||
|
"shape",
|
||||||
|
"polys",
|
||||||
|
"ignore_tags"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PostProcess": {
|
||||||
|
"name": "DBPostProcess",
|
||||||
|
"thresh": 0.3,
|
||||||
|
"box_thresh": 0.6,
|
||||||
|
"max_candidates": 1000,
|
||||||
|
"unclip_ratio": 1.5
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
filename,filesize,encoding,header␍
|
|
||||||
inference_1.onnx,50000000,,␍
|
|
||||||
inference_2.onnx,38118768,,␍
|
|
||||||
|
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
@@ -0,0 +1,53 @@
|
|||||||
|
Global:
|
||||||
|
model_name: PP-OCRv5_server_det
|
||||||
|
Hpi:
|
||||||
|
backend_configs:
|
||||||
|
paddle_infer:
|
||||||
|
trt_dynamic_shapes: &id001
|
||||||
|
x:
|
||||||
|
- - 1
|
||||||
|
- 3
|
||||||
|
- 32
|
||||||
|
- 32
|
||||||
|
- - 1
|
||||||
|
- 3
|
||||||
|
- 736
|
||||||
|
- 736
|
||||||
|
- - 1
|
||||||
|
- 3
|
||||||
|
- 4000
|
||||||
|
- 4000
|
||||||
|
tensorrt:
|
||||||
|
dynamic_shapes: *id001
|
||||||
|
PreProcess:
|
||||||
|
transform_ops:
|
||||||
|
- DecodeImage:
|
||||||
|
channel_first: false
|
||||||
|
img_mode: BGR
|
||||||
|
- DetLabelEncode: null
|
||||||
|
- DetResizeForTest:
|
||||||
|
resize_long: 960
|
||||||
|
- NormalizeImage:
|
||||||
|
mean:
|
||||||
|
- 0.485
|
||||||
|
- 0.456
|
||||||
|
- 0.406
|
||||||
|
order: hwc
|
||||||
|
scale: 1./255.
|
||||||
|
std:
|
||||||
|
- 0.229
|
||||||
|
- 0.224
|
||||||
|
- 0.225
|
||||||
|
- ToCHWImage: null
|
||||||
|
- KeepKeys:
|
||||||
|
keep_keys:
|
||||||
|
- image
|
||||||
|
- shape
|
||||||
|
- polys
|
||||||
|
- ignore_tags
|
||||||
|
PostProcess:
|
||||||
|
name: DBPostProcess
|
||||||
|
thresh: 0.3
|
||||||
|
box_thresh: 0.6
|
||||||
|
max_candidates: 1000
|
||||||
|
unclip_ratio: 1.5
|
||||||
Binary file not shown.
@@ -0,0 +1,111 @@
|
|||||||
|
{
|
||||||
|
"Global": {
|
||||||
|
"model_name": "PP-OCRv5_mobile_det"
|
||||||
|
},
|
||||||
|
"Hpi": {
|
||||||
|
"backend_configs": {
|
||||||
|
"paddle_infer": {
|
||||||
|
"trt_dynamic_shapes": {
|
||||||
|
"x": [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
32,
|
||||||
|
32
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
736,
|
||||||
|
736
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
4000,
|
||||||
|
4000
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tensorrt": {
|
||||||
|
"dynamic_shapes": {
|
||||||
|
"x": [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
32,
|
||||||
|
32
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
736,
|
||||||
|
736
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
4000,
|
||||||
|
4000
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PreProcess": {
|
||||||
|
"transform_ops": [
|
||||||
|
{
|
||||||
|
"DecodeImage": {
|
||||||
|
"channel_first": false,
|
||||||
|
"img_mode": "BGR"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DetLabelEncode": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DetResizeForTest": {
|
||||||
|
"resize_long": 960
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NormalizeImage": {
|
||||||
|
"mean": [
|
||||||
|
0.485,
|
||||||
|
0.456,
|
||||||
|
0.406
|
||||||
|
],
|
||||||
|
"order": "hwc",
|
||||||
|
"scale": "1./255.",
|
||||||
|
"std": [
|
||||||
|
0.229,
|
||||||
|
0.224,
|
||||||
|
0.225
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ToCHWImage": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"KeepKeys": {
|
||||||
|
"keep_keys": [
|
||||||
|
"image",
|
||||||
|
"shape",
|
||||||
|
"polys",
|
||||||
|
"ignore_tags"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"PostProcess": {
|
||||||
|
"name": "DBPostProcess",
|
||||||
|
"thresh": 0.3,
|
||||||
|
"box_thresh": 0.6,
|
||||||
|
"max_candidates": 1000,
|
||||||
|
"unclip_ratio": 1.5
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
@@ -0,0 +1,53 @@
|
|||||||
|
Global:
|
||||||
|
model_name: PP-OCRv5_mobile_det
|
||||||
|
Hpi:
|
||||||
|
backend_configs:
|
||||||
|
paddle_infer:
|
||||||
|
trt_dynamic_shapes: &id001
|
||||||
|
x:
|
||||||
|
- - 1
|
||||||
|
- 3
|
||||||
|
- 32
|
||||||
|
- 32
|
||||||
|
- - 1
|
||||||
|
- 3
|
||||||
|
- 736
|
||||||
|
- 736
|
||||||
|
- - 1
|
||||||
|
- 3
|
||||||
|
- 4000
|
||||||
|
- 4000
|
||||||
|
tensorrt:
|
||||||
|
dynamic_shapes: *id001
|
||||||
|
PreProcess:
|
||||||
|
transform_ops:
|
||||||
|
- DecodeImage:
|
||||||
|
channel_first: false
|
||||||
|
img_mode: BGR
|
||||||
|
- DetLabelEncode: null
|
||||||
|
- DetResizeForTest:
|
||||||
|
resize_long: 960
|
||||||
|
- NormalizeImage:
|
||||||
|
mean:
|
||||||
|
- 0.485
|
||||||
|
- 0.456
|
||||||
|
- 0.406
|
||||||
|
order: hwc
|
||||||
|
scale: 1./255.
|
||||||
|
std:
|
||||||
|
- 0.229
|
||||||
|
- 0.224
|
||||||
|
- 0.225
|
||||||
|
- ToCHWImage: null
|
||||||
|
- KeepKeys:
|
||||||
|
keep_keys:
|
||||||
|
- image
|
||||||
|
- shape
|
||||||
|
- polys
|
||||||
|
- ignore_tags
|
||||||
|
PostProcess:
|
||||||
|
name: DBPostProcess
|
||||||
|
thresh: 0.3
|
||||||
|
box_thresh: 0.6
|
||||||
|
max_candidates: 1000
|
||||||
|
unclip_ratio: 1.5
|
||||||
@@ -16,7 +16,5 @@ class SubtitleDetectMode(Enum):
|
|||||||
"""
|
"""
|
||||||
字幕检测算法枚举
|
字幕检测算法枚举
|
||||||
"""
|
"""
|
||||||
PP_OCRv4_SERVER = "PP-OCRv4-Server"
|
PP_OCRv5_MOBILE = "快速"
|
||||||
PP_OCRv4_MOBILE = "PP-OCRv4-Mobile"
|
PP_OCRv5_SERVER = "精准"
|
||||||
PP_OCRv5_SERVER = "PP-OCRv5-Server"
|
|
||||||
PP_OCRv5_MOBILE = "PP-OCRv5-Mobile"
|
|
||||||
@@ -3,6 +3,11 @@ from backend.config import config, BASE_DIR
|
|||||||
from backend.tools.common_tools import merge_big_file_if_not_exists
|
from backend.tools.common_tools import merge_big_file_if_not_exists
|
||||||
from backend.tools.constant import SubtitleDetectMode
|
from backend.tools.constant import SubtitleDetectMode
|
||||||
|
|
||||||
|
_MODEL_NAME_MAP = {
|
||||||
|
SubtitleDetectMode.PP_OCRv5_MOBILE: "PP-OCRv5_mobile_det",
|
||||||
|
SubtitleDetectMode.PP_OCRv5_SERVER: "PP-OCRv5_server_det",
|
||||||
|
}
|
||||||
|
|
||||||
class ModelConfig:
|
class ModelConfig:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.LAMA_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'big-lama')
|
self.LAMA_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'big-lama')
|
||||||
@@ -13,14 +18,9 @@ class ModelConfig:
|
|||||||
self.DET_MODEL_DIR = os.path.join(BASE_DIR,'models', 'V5', 'ch_det_fast')
|
self.DET_MODEL_DIR = os.path.join(BASE_DIR,'models', 'V5', 'ch_det_fast')
|
||||||
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv5_SERVER:
|
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv5_SERVER:
|
||||||
self.DET_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'V5', 'ch_det')
|
self.DET_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'V5', 'ch_det')
|
||||||
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv4_MOBILE:
|
|
||||||
self.DET_MODEL_DIR = os.path.join(BASE_DIR,'models', 'V4', 'ch_det_fast')
|
|
||||||
elif config.subtitleDetectMode.value == SubtitleDetectMode.PP_OCRv4_SERVER:
|
|
||||||
self.DET_MODEL_DIR = os.path.join(BASE_DIR, 'models', 'V4', 'ch_det')
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Invalid subtitle detect mode: {config.subtitleDetectMode.value}")
|
raise ValueError(f"Invalid subtitle detect mode: {config.subtitleDetectMode.value}")
|
||||||
|
self.DET_MODEL_NAME = _MODEL_NAME_MAP[config.subtitleDetectMode.value]
|
||||||
|
|
||||||
merge_big_file_if_not_exists(self.LAMA_MODEL_DIR, 'bit-lama.pt')
|
merge_big_file_if_not_exists(self.LAMA_MODEL_DIR, 'bit-lama.pt')
|
||||||
merge_big_file_if_not_exists(self.PROPAINTER_MODEL_DIR, 'ProPainter.pth')
|
merge_big_file_if_not_exists(self.PROPAINTER_MODEL_DIR, 'ProPainter.pth')
|
||||||
merge_big_file_if_not_exists(self.DET_MODEL_DIR, 'inference.onnx')
|
|
||||||
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
|
||||||
@@ -27,36 +26,37 @@ class SubtitleDetect:
|
|||||||
def text_detector(self):
|
def text_detector(self):
|
||||||
import paddle
|
import paddle
|
||||||
paddle.disable_signal_handler()
|
paddle.disable_signal_handler()
|
||||||
from paddleocr.tools.infer import utility
|
from paddleocr import TextDetection
|
||||||
from paddleocr.tools.infer.predict_det import TextDetector
|
|
||||||
hardware_accelerator = HardwareAccelerator.instance()
|
hardware_accelerator = HardwareAccelerator.instance()
|
||||||
onnx_providers = hardware_accelerator.onnx_providers
|
onnx_providers = hardware_accelerator.onnx_providers
|
||||||
model_config = ModelConfig()
|
model_config = ModelConfig()
|
||||||
parser = utility.init_args()
|
return TextDetection(
|
||||||
args = parser.parse_args([])
|
model_name=model_config.DET_MODEL_NAME,
|
||||||
args.det_algorithm = 'DB'
|
model_dir=model_config.DET_MODEL_DIR,
|
||||||
args.det_model_dir = os.path.join(model_config.DET_MODEL_DIR, 'inference.onnx') if len(onnx_providers) > 0 else model_config.DET_MODEL_DIR
|
device="cpu",
|
||||||
args.use_gpu=False
|
enable_hpi=len(onnx_providers) > 0,
|
||||||
args.use_onnx=len(onnx_providers) > 0
|
)
|
||||||
args.onnx_providers=onnx_providers
|
|
||||||
return TextDetector(args)
|
|
||||||
|
|
||||||
def detect_subtitle(self, img):
|
def detect_subtitle(self, img):
|
||||||
temp_list = []
|
temp_list = []
|
||||||
dt_boxes, elapse = self.text_detector(img)
|
results = self.text_detector.predict(img)
|
||||||
coordinate_list = get_coordinates(dt_boxes.tolist())
|
for res in results:
|
||||||
if coordinate_list:
|
dt_polys = res['dt_polys']
|
||||||
for coordinate in coordinate_list:
|
if dt_polys is None or len(dt_polys) == 0:
|
||||||
xmin, xmax, ymin, ymax = coordinate
|
continue
|
||||||
if self.sub_areas is not None and len(self.sub_areas) > 0:
|
coordinate_list = get_coordinates(dt_polys.tolist())
|
||||||
for sub_area in self.sub_areas:
|
if coordinate_list:
|
||||||
s_ymin, s_ymax, s_xmin, s_xmax = sub_area
|
for coordinate in coordinate_list:
|
||||||
if (s_xmin <= xmin and xmax <= s_xmax
|
xmin, xmax, ymin, ymax = coordinate
|
||||||
and s_ymin <= ymin
|
if self.sub_areas is not None and len(self.sub_areas) > 0:
|
||||||
and ymax <= s_ymax):
|
for sub_area in self.sub_areas:
|
||||||
temp_list.append((xmin, xmax, ymin, ymax))
|
s_ymin, s_ymax, s_xmin, s_xmax = sub_area
|
||||||
else:
|
if (s_xmin <= xmin and xmax <= s_xmax
|
||||||
temp_list.append((xmin, xmax, ymin, ymax))
|
and s_ymin <= ymin
|
||||||
|
and ymax <= s_ymax):
|
||||||
|
temp_list.append((xmin, xmax, ymin, ymax))
|
||||||
|
else:
|
||||||
|
temp_list.append((xmin, xmax, ymin, ymax))
|
||||||
return temp_list
|
return temp_list
|
||||||
|
|
||||||
def find_subtitle_frame_no(self, sub_remover=None):
|
def find_subtitle_frame_no(self, sub_remover=None):
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 405 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 26 KiB |
+20
-17
@@ -1,25 +1,28 @@
|
|||||||
albumentations~=1.4.10
|
|
||||||
filesplit==3.0.2
|
filesplit==3.0.2
|
||||||
opencv-python==4.11.0.86
|
opencv-python==4.11.0.86
|
||||||
scikit-image==0.25.2
|
scikit-image==0.25.2
|
||||||
imgaug==0.4.0
|
|
||||||
pyclipper==1.3.0.post6
|
|
||||||
lmdb==1.6.2
|
|
||||||
PyYAML==6.0.2
|
|
||||||
omegaconf==2.3.0
|
|
||||||
tqdm==4.67.1
|
tqdm==4.67.1
|
||||||
pyside6-fluent-widgets==1.7.7
|
pyside6-fluent-widgets==1.7.7
|
||||||
easydict==1.13
|
|
||||||
scikit-learn==1.6.1
|
|
||||||
pandas==2.2.3
|
|
||||||
webdataset==0.2.111
|
|
||||||
numpy==2.2.5
|
numpy==2.2.5
|
||||||
protobuf==6.30.2
|
av==17.0.0
|
||||||
av==14.3.0
|
|
||||||
einops==0.8.1
|
einops==0.8.1
|
||||||
paddleocr==2.10.0
|
paddleocr==3.4.0
|
||||||
onnxruntime-gpu==1.20.1; sys_platform == 'linux'
|
matplotlib
|
||||||
|
Pillow
|
||||||
|
scipy
|
||||||
|
requests
|
||||||
|
darkdetect
|
||||||
|
je-showinfilemanager==1.1.6a4
|
||||||
|
# torch and torchvision are installed separately (see Dockerfile for platform-specific versions)
|
||||||
|
|
||||||
|
# Training only
|
||||||
|
#matplotlib
|
||||||
|
#lpips
|
||||||
|
#tensorboardX
|
||||||
|
|
||||||
|
# Hardware acceleration
|
||||||
|
#onnxruntime-gpu==1.20.1; sys_platform == 'linux'
|
||||||
|
|
||||||
# do not upgrade, windows 10/11 compatable issues, check hardware_acclerator.py:100
|
# do not upgrade, windows 10/11 compatable issues, check hardware_acclerator.py:100
|
||||||
onnxruntime-directml==1.20.1; sys_platform == 'win32'
|
#onnxruntime-directml==1.20.1; sys_platform == 'win32'
|
||||||
onnxruntime==1.22.0; sys_platform == 'darwin'
|
#onnxruntime==1.22.0; sys_platform == 'darwin'
|
||||||
je-showinfilemanager==1.1.6a4
|
|
||||||
|
|||||||
Reference in New Issue
Block a user