返回 Social Auto Upload
login_qrcode.py
根目录 / utils / login_qrcode.py
1 # -*- coding: utf-8 -*-
2 from datetime import datetime
3 import base64
4 from pathlib import Path
5 import sys
6
7 import cv2
8 import numpy as np
9 import segno
10
11
12 def build_login_qrcode_path(account_file: str, suffix: str = "login_qrcode") -> Path:
13 account_path = Path(account_file)
14 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
15 return account_path.with_name(f"{account_path.stem}_{suffix}_{timestamp}.png")
16
17
18 def save_data_url_image(data_url: str, output_path: Path) -> Path:
19 if not data_url.startswith("data:image/"):
20 raise ValueError("二维码地址不是 data:image 格式")
21
22 header, encoded = data_url.split(",", 1)
23 if ";base64" not in header:
24 raise ValueError("二维码图片不是 base64 编码")
25
26 output_path.parent.mkdir(parents=True, exist_ok=True)
27 output_path.write_bytes(base64.b64decode(encoded))
28 return output_path
29
30
31 def remove_qrcode_file(qrcode_path: Path | None) -> bool:
32 if qrcode_path and qrcode_path.exists():
33 qrcode_path.unlink()
34 return True
35 return False
36
37
38 def decode_qrcode_from_path(qrcode_path: Path) -> str | None:
39 # Windows 下 cv2.imread 对中文路径不稳定,优先走 numpy+imdecode
40 image = None
41 try:
42 data = np.fromfile(str(qrcode_path), dtype=np.uint8)
43 if data.size > 0:
44 image = cv2.imdecode(data, cv2.IMREAD_COLOR)
45 except Exception:
46 image = None
47 if image is None:
48 image = cv2.imread(str(qrcode_path))
49 if image is None:
50 return None
51
52 detector = cv2.QRCodeDetector()
53 qrcode_content, _, _ = detector.detectAndDecode(image)
54 return qrcode_content or None
55
56
57 def _print_ascii_qrcode(qrcode) -> None:
58 border = 1
59 rows = list(qrcode.matrix)
60 empty_line = " " * (len(rows[0]) + border * 2)
61 print(empty_line)
62 for row in rows:
63 line = [" "] * border
64 line.extend("##" if cell else " " for cell in row)
65 line.extend([" "] * border)
66 print("".join(line))
67 print(empty_line)
68
69
70 def print_terminal_qrcode(
71 qrcode_content: str,
72 qrcode_path: Path,
73 app_name: str,
74 compact: bool = True,
75 border: int = 0,
76 ) -> None:
77 print()
78 print(f"请使用{app_name}扫描下方二维码登录:")
79 qrcode = segno.make(qrcode_content, error="L", boost_error=False)
80 try:
81 if hasattr(sys.stdout, "reconfigure"):
82 sys.stdout.reconfigure(encoding="utf-8")
83 qrcode.terminal(compact=compact, border=border)
84 except (UnicodeEncodeError, OSError):
85 print("当前终端不支持 Unicode 二维码字符,已切换为 ASCII 打印:")
86 _print_ascii_qrcode(qrcode)
87 print("在 Windows 下建议使用 Windows Terminal(支持 UTF-8,可完整显示二维码)")
88 print(f"否则请打开 {qrcode_path} 扫码")
89 print()
90
90 lines PYTHON