吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 952|回复: 2
收起左侧

[Python 原创] 基于python原生库的微信 / QQ 缓存安全清理工具

[复制链接]
Serendisand 发表于 2026-7-30 10:05
本帖最后由 Serendisand 于 2026-7-30 13:20 编辑

微信 / QQ 缓存安全清理工具

一个只扫描、不自动删除的 Windows 本地清理工具。它只在指定的微信、QQ 数据目录中寻找规则明确的头像缓存和缩略图缓存,并把每一个候选文件的完整路径、类别和大小展示给用户。删除操作必须由用户在界面中选中并二次确认。

安全边界

  • 默认目录:文档/WeChat Files、文档/Tencent Files,以及常见的微信 AppData 目录(存在时才扫描)。可自行添加目录。
  • 不扫描聊天记录数据库、文档、视频、原图、语音或任意未知文件。
  • 仅匹配以下规则:
    • 头像缓存:路径中含 avatar、headimage 或 headimg,扩展名为 .dat。
    • 缩略图缓存:路径中含 thumb 或 thumbnail,扩展名为 .dat、.jpg、.jpeg、.png、.webp、.bmp。
  • 文件还须落在界面设定的大小范围内(默认 1 KiB–20 MiB)。
  • 不递归跟随目录链接;无权读取的目录会跳过并记录在扫描提示中。
  • 删除前会在程序目录的 删除清单 文件夹中生成 UTF-8 .txt 清单,包含时间、路径、大小、规则和删除结果。
  • 清单是审计记录,不含文件内容,不能用于恢复文件。请先检查列表;程序不会代替用户判断文件是否可删。

运行

需要 Python 3.10+,只使用标准库:

python wechat_qq_cleaner.py

在 Windows 中也可以双击运行(若 .py 已关联 Python)。

使用方式

  1. 关闭微信和 QQ,避免文件正在写入或占用。
  2. 启动程序,确认或添加要扫描的根目录。
  3. 设置体积范围后点击 开始安全扫描。
  4. 在结果列表中按住 Ctrl / Shift 多选;点击 删除所选文件。
  5. 阅读确认窗口。程序会先写入删除清单,再逐个删除选定文件。

建议第一次只删除少量文件并在客户端中确认无异常。重要资料请自行备份.

源码

from __future__ import annotations

import os
import queue
import threading
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

APP_TITLE = "微信 / QQ 缓存安全清理"
MANIFEST_DIR_NAME = "删除清单"

@dataclass(frozen=True)
class CacheRule:
    key: str
    label: str
    description: str
    extensions: tuple[str, ...]
    path_keywords: tuple[str, ...]

    def matches(self, file_path: Path) -> bool:
        path_text = str(file_path).lower()
        return (
            file_path.suffix.lower() in self.extensions
            and any(keyword in path_text for keyword in self.path_keywords)
        )

CACHE_RULES = (
    CacheRule(
        "avatar",
        "头像缓存",
        "仅限路径含 avatar / headimage / headimg 的 .dat 文件",
        (".dat",),
        ("avatar", "headimage", "headimg"),
    ),
    CacheRule(
        "thumbnail",
        "图片缩略图缓存",
        "仅限路径含 thumb / thumbnail 的常见小图片或 .dat 文件",
        (".dat", ".jpg", ".jpeg", ".png", ".webp", ".bmp"),
        ("thumb", "thumbnail"),
    ),
    CacheRule(
        "sticker",
        "表情包缓存",
        "仅限路径含 emoji / sticker / emoticon 的常见图片或 .dat 文件",
        (".dat", ".gif", ".jpg", ".jpeg", ".png", ".webp"),
        ("emoji", "sticker", "emoticon"),
    ),
)

@dataclass
class ScanItem:
    path: Path
    size: int
    category: str
    rule_description: str

def format_size(size: int) -> str:
    units = ("B", "KiB", "MiB", "GiB", "TiB")
    value = float(size)
    for unit in units:
        if value < 1024 or unit == units[-1]:
            return f"{value:.1f} {unit}" if unit != "B" else f"{int(value)} B"
        value /= 1024
    return f"{size} B"

def default_scan_roots() -> list[Path]:
    home = Path.home()
    candidates = (
        home / "Documents" / "WeChat Files",
        home / "文档" / "WeChat Files",
        home / "Documents" / "Tencent Files",
        home / "文档" / "Tencent Files",
        home / "AppData" / "Roaming" / "Tencent" / "WeChat",
        home / "AppData" / "Roaming" / "Tencent" / "QQ",
    )
    seen: set[str] = set()
    roots: list[Path] = []
    for candidate in candidates:
        normalized = os.path.normcase(os.path.normpath(str(candidate)))
        if candidate.is_dir() and normalized not in seen:
            roots.append(candidate)
            seen.add(normalized)
    return roots

class CleanerApp(tk.Tk):
    def __init__(self) -> None:
        super().__init__()
        self.title(APP_TITLE)
        self.geometry("1220x760")
        self.minsize(980, 620)

        self.items: dict[str, ScanItem] = {}
        self.events: queue.Queue[tuple[str, object]] = queue.Queue()
        self.scanning = False

        self.rule_vars = {rule.key: tk.BooleanVar(value=True) for rule in CACHE_RULES}
        self.min_kib_var = tk.StringVar(value="1")
        self.max_mib_var = tk.StringVar(value="20")
        self.status_var = tk.StringVar(value="请选择要扫描的缓存类型,然后开始安全扫描。")
        self.summary_var = tk.StringVar(value="当前没有扫描结果")
        self.selection_var = tk.StringVar(value="已选 0 个文件,共 0 B")

        self._build_ui()
        self._add_default_roots()
        self.after(100, self._process_events)

    def _build_ui(self) -> None:
        self.configure(bg="#f4faf7")
        style = ttk.Style(self)
        style.theme_use("clam")
        style.configure("App.TFrame", background="#f4faf7")
        style.configure("Card.TFrame", background="#ffffff")
        style.configure("Title.TLabel", background="#f4faf7", foreground="#173b35", font=("Microsoft YaHei UI", 18, "bold"))
        style.configure("Subtitle.TLabel", background="#f4faf7", foreground="#62807a", font=("Microsoft YaHei UI", 10))
        style.configure("Section.TLabelframe", background="#ffffff", bordercolor="#dcebe5", relief="solid")
        style.configure("Section.TLabelframe.Label", background="#ffffff", foreground="#286b5f", font=("Microsoft YaHei UI", 10, "bold"))
        style.configure("TLabel", background="#ffffff", foreground="#28453f", font=("Microsoft YaHei UI", 9))
        style.configure("Hint.TLabel", background="#ffffff", foreground="#728a84", font=("Microsoft YaHei UI", 8))
        style.configure("Primary.TButton", background="#329a83", foreground="#ffffff", borderwidth=0, padding=(16, 8), font=("Microsoft YaHei UI", 9, "bold"))
        style.map("Primary.TButton", background=[("active", "#237b68"), ("disabled", "#b8d9d0")])
        style.configure("Soft.TButton", background="#e6f4ef", foreground="#237b68", borderwidth=0, padding=(12, 7))
        style.map("Soft.TButton", background=[("active", "#d2ebe3")])
        style.configure("Danger.TButton", background="#fff0ee", foreground="#b95044", borderwidth=0, padding=(12, 7))
        style.map("Danger.TButton", background=[("active", "#fbded9")])
        style.configure("Treeview", background="#ffffff", fieldbackground="#ffffff", foreground="#28453f", rowheight=31, font=("Microsoft YaHei UI", 9), borderwidth=0)
        style.configure("Treeview.Heading", background="#e9f5f0", foreground="#286b5f", relief="flat", font=("Microsoft YaHei UI", 9, "bold"), padding=(8, 8))
        style.map("Treeview", background=[("selected", "#cfece3")], foreground=[("selected", "#173b35")])

        page = ttk.Frame(self, style="App.TFrame", padding=(22, 18, 22, 14))
        page.pack(fill=tk.BOTH, expand=True)

        header = ttk.Frame(page, style="App.TFrame")
        header.pack(fill=tk.X, pady=(0, 14))
        ttk.Label(header, text="微信 / QQ 缓存安全清理", style="Title.TLabel").pack(anchor=tk.W)
        ttk.Label(
            header,
            text="只扫描已选择的明确缓存类型 · 文件由你逐项确认后才会删除",
            style="Subtitle.TLabel",
        ).pack(anchor=tk.W, pady=(4, 0))

        top = ttk.Frame(page, style="App.TFrame")
        top.pack(fill=tk.X)

        type_box = ttk.LabelFrame(top, text="  ① 选择要扫描的缓存类型  ", style="Section.TLabelframe", padding=14)
        type_box.pack(fill=tk.X)
        for index, rule in enumerate(CACHE_RULES):
            rule_frame = ttk.Frame(type_box, style="Card.TFrame", padding=(3, 2))
            rule_frame.grid(row=0, column=index, sticky=tk.NSEW, padx=(0, 24 if index < len(CACHE_RULES) - 1 else 0))
            ttk.Checkbutton(rule_frame, text=rule.label, variable=self.rule_vars[rule.key]).pack(anchor=tk.W)
            ttk.Label(rule_frame, text=rule.description, style="Hint.TLabel", wraplength=265).pack(anchor=tk.W, pady=(3, 0))
            type_box.columnconfigure(index, weight=1)

        limit_box = ttk.Frame(top, style="Card.TFrame", padding=(4, 12, 4, 0))
        limit_box.pack(fill=tk.X)
        ttk.Label(limit_box, text="文件体积范围:").pack(side=tk.LEFT)
        ttk.Entry(limit_box, textvariable=self.min_kib_var, width=8).pack(side=tk.LEFT)
        ttk.Label(limit_box, text=" KiB  至 ").pack(side=tk.LEFT)
        ttk.Entry(limit_box, textvariable=self.max_mib_var, width=8).pack(side=tk.LEFT)
        ttk.Label(limit_box, text=" MiB", style="Hint.TLabel").pack(side=tk.LEFT)
        ttk.Label(limit_box, text="范围外的文件不会进入结果列表", style="Hint.TLabel").pack(side=tk.LEFT, padx=(12, 0))

        roots_box = ttk.LabelFrame(page, text="  ② 扫描位置(仅限下列目录)  ", style="Section.TLabelframe", padding=12)
        roots_box.pack(fill=tk.X, pady=(12, 10))
        self.roots_listbox = tk.Listbox(
            roots_box, height=4, selectmode=tk.EXTENDED, relief=tk.FLAT, borderwidth=0,
            background="#f8fcfa", foreground="#28453f", selectbackground="#cfece3",
            selectforeground="#173b35", font=("Microsoft YaHei UI", 9), highlightthickness=0,
        )
        self.roots_listbox.pack(side=tk.LEFT, fill=tk.X, expand=True)
        root_buttons = ttk.Frame(roots_box, style="Card.TFrame")
        root_buttons.pack(side=tk.LEFT, fill=tk.Y, padx=(12, 0))
        ttk.Button(root_buttons, text="添加目录", style="Soft.TButton", command=self._add_root).pack(fill=tk.X)
        ttk.Button(root_buttons, text="移除选中", style="Soft.TButton", command=self._remove_selected_roots).pack(fill=tk.X, pady=(7, 0))

        actions = ttk.Frame(page, style="App.TFrame", padding=(0, 2))
        actions.pack(fill=tk.X)
        self.scan_button = ttk.Button(actions, text="开始安全扫描", style="Primary.TButton", command=self._start_scan)
        self.scan_button.pack(side=tk.LEFT)
        self.delete_button = ttk.Button(actions, text="删除所选文件", style="Danger.TButton", command=self._delete_selected)
        self.delete_button.pack(side=tk.LEFT, padx=(8, 0))
        ttk.Button(actions, text="全选结果", style="Soft.TButton", command=self._select_all_results).pack(side=tk.LEFT, padx=(18, 0))
        ttk.Button(actions, text="清空结果", style="Soft.TButton", command=self._clear_results).pack(side=tk.LEFT, padx=(8, 0))
        ttk.Label(actions, textvariable=self.summary_var, style="Subtitle.TLabel").pack(side=tk.RIGHT, pady=(5, 0))

        table_card = ttk.LabelFrame(page, text="  ③ 检查扫描结果并手动选择  ", style="Section.TLabelframe", padding=8)
        table_card.pack(fill=tk.BOTH, expand=True, pady=(8, 0))
        table_box = ttk.Frame(table_card, style="Card.TFrame")
        table_box.pack(fill=tk.BOTH, expand=True)
        columns = ("category", "size", "path", "rule")
        self.tree = ttk.Treeview(table_box, columns=columns, show="headings", selectmode="extended")
        self.tree.heading("category", text="类型")
        self.tree.heading("size", text="大小")
        self.tree.heading("path", text="完整路径")
        self.tree.heading("rule", text="匹配规则")
        self.tree.column("category", width=120, stretch=False)
        self.tree.column("size", width=105, stretch=False, anchor=tk.E)
        self.tree.column("path", width=650, stretch=True)
        self.tree.column("rule", width=300, stretch=True)
        self.tree.bind("<<TreeviewSelect>>", self._update_selection_summary)
        vertical = ttk.Scrollbar(table_box, orient=tk.VERTICAL, command=self.tree.yview)
        horizontal = ttk.Scrollbar(table_box, orient=tk.HORIZONTAL, command=self.tree.xview)
        self.tree.configure(yscrollcommand=vertical.set, xscrollcommand=horizontal.set)
        self.tree.grid(row=0, column=0, sticky=tk.NSEW)
        vertical.grid(row=0, column=1, sticky=tk.NS)
        horizontal.grid(row=1, column=0, sticky=tk.EW)
        table_box.rowconfigure(0, weight=1)
        table_box.columnconfigure(0, weight=1)

        footer = ttk.Frame(page, style="App.TFrame", padding=(2, 9, 2, 0))
        footer.pack(fill=tk.X)
        ttk.Label(footer, textvariable=self.selection_var, style="Subtitle.TLabel").pack(side=tk.LEFT)
        ttk.Label(footer, text="删除前会生成可追溯的 .txt 清单", style="Subtitle.TLabel").pack(side=tk.RIGHT)

        status = ttk.Label(self, textvariable=self.status_var, relief=tk.FLAT, anchor=tk.W, padding=(18, 7), background="#e4f2ed", foreground="#286b5f")
        status.pack(fill=tk.X, side=tk.BOTTOM)

    def _add_default_roots(self) -> None:
        for root in default_scan_roots():
            self.roots_listbox.insert(tk.END, str(root))
        if self.roots_listbox.size() == 0:
            self.status_var.set("未发现默认微信/QQ目录,请使用“添加目录”选择 WeChat Files 或 Tencent Files。")

    def _add_root(self) -> None:
        selected = filedialog.askdirectory(title="选择 WeChat Files、Tencent Files 或其子目录")
        if not selected:
            return
        normalized = os.path.normcase(os.path.normpath(selected))
        existing = {
            os.path.normcase(os.path.normpath(self.roots_listbox.get(index)))
            for index in range(self.roots_listbox.size())
        }
        if normalized not in existing:
            self.roots_listbox.insert(tk.END, selected)

    def _remove_selected_roots(self) -> None:
        for index in reversed(self.roots_listbox.curselection()):
            self.roots_listbox.delete(index)

    def _selected_rules(self) -> list[CacheRule]:
        return [rule for rule in CACHE_RULES if self.rule_vars[rule.key].get()]

    def _parse_limits(self) -> tuple[int, int] | None:
        try:
            min_size = int(float(self.min_kib_var.get()) * 1024)
            max_size = int(float(self.max_mib_var.get()) * 1024 * 1024)
        except ValueError:
            messagebox.showerror(APP_TITLE, "文件体积范围必须是数字。")
            return None
        if min_size < 0 or max_size < min_size:
            messagebox.showerror(APP_TITLE, "请设置有效的文件体积范围。")
            return None
        return min_size, max_size

    def _start_scan(self) -> None:
        if self.scanning:
            return
        rules = self._selected_rules()
        if not rules:
            messagebox.showwarning(APP_TITLE, "请至少选择一种缓存类型。")
            return
        roots = [Path(self.roots_listbox.get(i)) for i in range(self.roots_listbox.size())]
        roots = [root for root in roots if root.is_dir()]
        if not roots:
            messagebox.showwarning(APP_TITLE, "请添加至少一个存在的扫描目录。")
            return
        limits = self._parse_limits()
        if limits is None:
            return

        self._clear_results()
        self.scanning = True
        self.scan_button.configure(state=tk.DISABLED)
        self.delete_button.configure(state=tk.DISABLED)
        self.status_var.set("正在安全扫描:只读取文件名、路径与大小,不会删除任何文件……")
        threading.Thread(target=self._scan_worker, args=(roots, rules, *limits), daemon=True).start()

    def _scan_worker(self, roots: list[Path], rules: list[CacheRule], min_size: int, max_size: int) -> None:
        scanned = matched = skipped = 0
        seen_files: set[str] = set()

        def on_walk_error(_: OSError) -> None:
            nonlocal skipped
            skipped += 1

        for root in roots:
            for current_dir, directories, files in os.walk(root, topdown=True, followlinks=False, onerror=on_walk_error):
                # 跳过目录链接,避免绕出用户选择的范围或重复扫描。
                directories[:] = [
                    directory for directory in directories
                    if not Path(current_dir, directory).is_symlink()
                ]
                for name in files:
                    scanned += 1
                    file_path = Path(current_dir, name)
                    try:
                        if file_path.is_symlink():
                            continue
                        stat = file_path.stat()
                    except OSError:
                        skipped += 1
                        continue
                    if not min_size <= stat.st_size <= max_size:
                        continue
                    matching_rule = next((rule for rule in rules if rule.matches(file_path)), None)
                    if matching_rule is None:
                        continue
                    normalized = os.path.normcase(os.path.normpath(str(file_path)))
                    if normalized in seen_files:
                        continue
                    seen_files.add(normalized)
                    matched += 1
                    self.events.put(("item", ScanItem(file_path, stat.st_size, matching_rule.label, matching_rule.description)))
                    if matched % 50 == 0:
                        self.events.put(("progress", (scanned, matched)))
        self.events.put(("done", (scanned, matched, skipped)))

    def _process_events(self) -> None:
        try:
            while True:
                event, payload = self.events.get_nowait()
                if event == "item":
                    item = payload
                    assert isinstance(item, ScanItem)
                    item_id = self.tree.insert("", tk.END, values=(item.category, format_size(item.size), str(item.path), item.rule_description))
                    self.items[item_id] = item
                elif event == "progress":
                    scanned, matched = payload
                    self.status_var.set(f"正在扫描:已检查 {scanned:,} 个文件,找到 {matched:,} 个候选缓存……")
                elif event == "done":
                    scanned, matched, skipped = payload
                    self.scanning = False
                    self.scan_button.configure(state=tk.NORMAL)
                    self.delete_button.configure(state=tk.NORMAL)
                    self.summary_var.set(f"找到 {matched:,} 个候选文件,共 {format_size(self._total_size())}")
                    self._update_selection_summary()
                    extra = f";跳过 {skipped:,} 个无权读取或已失效项目" if skipped else ""
                    self.status_var.set(f"扫描完成:检查 {scanned:,} 个文件,匹配 {matched:,} 个候选缓存{extra}。请检查路径后再删除。")
        except queue.Empty:
            pass
        self.after(100, self._process_events)

    def _total_size(self, item_ids: tuple[str, ...] | None = None) -> int:
        target_ids = item_ids if item_ids is not None else tuple(self.items)
        return sum(self.items[item_id].size for item_id in target_ids if item_id in self.items)

    def _update_selection_summary(self, _: object | None = None) -> None:
        selected_ids = self.tree.selection()
        self.selection_var.set(
            f"已选 {len(selected_ids):,} 个文件,共 {format_size(self._total_size(selected_ids))}"
        )

    def _select_all_results(self) -> None:
        children = self.tree.get_children()
        self.tree.selection_set(children)
        self._update_selection_summary()
        if children:
            self.status_var.set(f"已选中 {len(children):,} 个候选文件,共 {format_size(self._total_size(children))}。")

    def _clear_results(self) -> None:
        self.tree.delete(*self.tree.get_children())
        self.items.clear()
        self.summary_var.set("当前没有扫描结果")
        self._update_selection_summary()

    def _delete_selected(self) -> None:
        selected_ids = self.tree.selection()
        if not selected_ids:
            messagebox.showinfo(APP_TITLE, "请在列表中选择要删除的文件。可使用 Ctrl 或 Shift 多选。")
            return
        selected = [self.items[item_id] for item_id in selected_ids if item_id in self.items]
        if not selected:
            return
        total_size = sum(item.size for item in selected)
        text = (
            f"即将删除 {len(selected):,} 个已选文件,合计 {format_size(total_size)}。\n\n"
            "程序会先生成删除清单(.txt),随后逐个删除文件。\n"
            "删除清单仅记录路径和结果,不能恢复文件内容。\n\n"
            "请确认已检查过列表中的完整路径。是否继续?"
        )
        if not messagebox.askyesno("最终确认删除", text, icon=messagebox.WARNING):
            return

        manifest_path = self._write_manifest(selected)
        deleted = failed = 0
        failures: list[str] = []
        for item in selected:
            try:
                # 删除前再次验证:拒绝删除符号链接与目录。
                if item.path.is_symlink() or not item.path.is_file():
                    raise OSError("文件已不存在、不是普通文件,或为链接")
                item.path.unlink()
                deleted += 1
                result = "已删除"
            except OSError as error:
                failed += 1
                result = f"失败:{error}"
                failures.append(f"{item.path} — {error}")
            self._append_manifest_result(manifest_path, item, result)

        for item_id in selected_ids:
            if item_id in self.items and not self.items[item_id].path.exists():
                self.tree.delete(item_id)
                del self.items[item_id]
        self.summary_var.set(f"剩余 {len(self.items):,} 个候选文件,共 {format_size(self._total_size())}")
        self._update_selection_summary()
        self.status_var.set(f"删除结束:成功 {deleted:,} 个,失败 {failed:,} 个。删除清单:{manifest_path}")
        detail = "\n".join(failures[:5])
        suffix = f"\n\n部分失败原因:\n{detail}" if detail else ""
        messagebox.showinfo(APP_TITLE, f"删除结束:成功 {deleted:,} 个,失败 {failed:,} 个。\n\n删除清单:\n{manifest_path}{suffix}")

    def _manifest_folder(self) -> Path:
        folder = Path(__file__).resolve().parent / MANIFEST_DIR_NAME
        folder.mkdir(exist_ok=True)
        return folder

    def _write_manifest(self, items: list[ScanItem]) -> Path:
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        manifest_path = self._manifest_folder() / f"删除清单_{timestamp}.txt"
        lines = [
            "微信 / QQ 缓存安全清理 — 删除前清单",
            f"生成时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
            f"选中文件数量:{len(items)}",
            f"选中文件总大小:{format_size(sum(item.size for item in items))}",
            "",
            "以下项目由用户在界面中手动选中。删除结果会追加在每一项下方。",
            "此文件是审计清单,不保存缓存内容,不能用于恢复。",
            "=" * 78,
        ]
        for number, item in enumerate(items, 1):
            lines.extend((
                f"[{number}] 类型:{item.category}",
                f"路径:{item.path}",
                f"大小:{format_size(item.size)} ({item.size} 字节)",
                f"匹配规则:{item.rule_description}",
                "删除结果:等待执行",
                "-" * 78,
            ))
        manifest_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
        return manifest_path

    @staticmethod
    def _append_manifest_result(manifest_path: Path, item: ScanItem, result: str) -> None:
        # 追加每项结果,确保删除途中失败/退出时仍保留可追溯记录。
        with manifest_path.open("a", encoding="utf-8") as file:
            file.write(f"执行结果 | {item.path} | {result}\n")

if __name__ == "__main__":
    CleanerApp().mainloop()

免费评分

参与人数 2吾爱币 +8 热心值 +2 收起 理由
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
ioyr5995 + 1 + 1 热心回复!

查看全部评分

发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

LLYYJJ 发表于 2026-8-19 14:00
好东西啊,先收藏了
C9527C 发表于 2026-9-19 22:51
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-11-6 04:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表