# -*- coding: utf-8 -*-
"""上传图片到百家号：分步注入 base64 + fetch 上传"""
import sys, socket, json, time, os, glob, base64
sys.stdout.reconfigure(encoding="utf-8")

HOST = "localhost"
PORT = 28800
import urllib.request as ur
pages = json.loads(ur.urlopen("http://127.0.0.1:28800/json").read())
PAGE_ID = pages[0]["id"]

imgs = glob.glob(r"D:\wxpic\*.jpg") + glob.glob(r"D:\wxpic\*.png")
IMG_PATH = max(imgs, key=os.path.getmtime)
print("[INFO] IMG:", IMG_PATH)

with open(IMG_PATH, "rb") as f:
    IMG_B64 = base64.b64encode(f.read()).decode()

import urllib.parse
u = "ws://%s:%s/devtools/page/%s" % (HOST, PORT, PAGE_ID)
p = urllib.parse.urlparse(u)
s = socket.create_connection((p.hostname, p.port or 80), timeout=15)
req = ("GET %s HTTP/1.1\r\nHost: %s:%s\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\n\r\n") % (p.path, p.hostname, p.port)
s.send(req.encode())
resp = b""
while b"\r\n\r\n" not in resp:
    resp += s.recv(4096)

def ws_send(data):
    data = data.encode("utf-8"); n = len(data); m = b"\x01\x02\x03\x04"
    if n <= 125: h = bytes([0x81, n | 0x80]) + m
    elif n <= 65535: h = bytes([0x81, 0xFE]) + n.to_bytes(2, "big") + m
    else: h = bytes([0x81, 0xFF]) + n.to_bytes(8, "big") + m
    s.send(h + bytes(data[i] ^ m[i % 4] for i in range(n)))

def ws_recv():
    h = b""
    while len(h) < 2: h += s.recv(2 - len(h))
    n = h[1] & 0x7F
    if n == 126:
        nb = b""
        while len(nb) < 2: nb += s.recv(2 - len(nb))
        n = int.from_bytes(nb, "big")
    elif n == 127:
        nb = b""
        while len(nb) < 8: nb += s.recv(8 - len(nb))
        n = int.from_bytes(nb, "big")
    body = b""
    while len(body) < n: body += s.recv(n - len(body))
    return body.decode("utf-8")

_mid = [0]

def cdp(method, params=None):
    if params is None: params = {}
    _mid[0] += 1
    ws_send(json.dumps({"id": _mid[0], "method": method, "params": params}))
    s.settimeout(30)
    for _ in range(600):
        try:
            r = json.loads(ws_recv())
            if r.get("id") == _mid[0]: return r
        except: pass
    return None

# Step 1: 注入 base64（分块）
print("\n[1] 注入 base64...")
chunk_size = 500000
for i in range(0, len(IMG_B64), chunk_size):
    chunk = IMG_B64[i:i+chunk_size]
    r = cdp("Runtime.evaluate", {
        "expression": "window.__IMG_B64__ = window.__IMG_B64__ || ''; window.__IMG_B64__ += '%s'" % chunk,
        "returnByValue": True
    })
r = cdp("Runtime.evaluate", {"expression": "window.__IMG_B64__.length", "returnByValue": True})
length = r.get("result", {}).get("result", {}).get("value", 0)
print("  base64 length:", length)

# Step 2: fetch 上传
print("\n[2] fetch 上传...")
r = cdp("Runtime.evaluate", {
    "expression": """
    async () => {
      try {
        const byteString = atob(window.__IMG_B64__);
        const ab = new ArrayBuffer(byteString.length);
        const ia = new Uint8Array(ab);
        for (let j = 0; j < byteString.length; j++) ia[j] = byteString.charCodeAt(j);
        const blob = new Blob([ab], {type: 'image/jpeg'});
        const file = new File([blob], 'cover.jpg', {type: 'image/jpeg'});
        const fd = new FormData();
        fd.append('media', file);
        const resp = await fetch('https://baijiahao.baidu.com/materialui/picture/uploadProxy', {
          method: 'POST', body: fd, credentials: 'include'
        });
        const text = await resp.text();
        return JSON.stringify({s: resp.status, b: text.substring(0, 500)});
      } catch(e) { return JSON.stringify({err: e.message}); }
    }
    """,
    "returnByValue": True,
    "awaitPromise": True
})
val = r.get("result", {}).get("result", {}).get("value", "")
if isinstance(val, dict): val = json.dumps(val, ensure_ascii=False)
print("  结果:", str(val)[:500])

s.close()
print("\nDone")
