# -*- coding: utf-8 -*-
"""通过 Cheetah 组件库找封面上传 API"""
import sys, socket, json, time, base64, os, glob
from base64 import b64encode
sys.stdout.reconfigure(encoding='utf-8')
HOST = "localhost"; PORT = 28800
PAGE_ID = "70039F329097C14448996F189E3A42A1"

# 读图片
IMG_LIST = glob.glob(r'D:\wxpic\*.jpg') + glob.glob(r'D:\wxpic\*.png')
IMG_PATH = max(IMG_LIST, key=os.path.getmtime) if IMG_LIST else None
with open(IMG_PATH, 'rb') as f:
    IMG_B64 = b64encode(f.read()).decode()
ext = os.path.splitext(IMG_PATH)[1].lower()
IMG_MIME = 'image/jpeg' if ext in ['.jpg','.jpeg'] else 'image/png'
print("[INFO] 图片:", IMG_PATH, "size:", len(IMG_B64))

def ws():
    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)
    return s

def send(s, d):
    d = d.encode('utf-8'); n = len(d); 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(d[i]^m[i%4] for i in range(n)))

def recv(s):
    def rx(n):
        b = b''
        while len(b) < n: b += s.recv(n-len(b))
        return b
    h = rx(2); n = h[1]&0x7f
    if n == 126: n = int.from_bytes(rx(2),'big')
    elif n == 127: n = int.from_bytes(rx(8),'big')
    return rx(n).decode('utf-8')

_mid = 0
def cdp(s, js, timeout=20):
    global _mid
    _mid += 1
    send(s, json.dumps({'id':_mid,'method':'Runtime.evaluate','params':{'expression':js,'returnByValue':True}}))
    s.settimeout(timeout)
    for _ in range(300):
        try:
            r = json.loads(recv(s))
            if r.get('id') == _mid:
                return r.get('result',{}).get('result',{}).get('value','')
        except: pass
    return ''

s = ws()
print("[OK] Connected\n")

# 1. 找 Cheetah 全局 API
r = cdp(s, """
(function() {
  var result = [];
  for (var k in window) {
    if (k.toLowerCase().indexOf('cheetah') > -1 ||
        k.toLowerCase().indexOf('upload') > -1 ||
        k.toLowerCase().indexOf('bjd') > -1 ||
        k.indexOf('$bj') > -1 ||
        k.indexOf('__bj') > -1) {
      try {
        var v = window[k];
        result.push({name: k, type: typeof v, preview: typeof v === 'function' ? v.toString().substring(0,60) : String(v).substring(0,40)});
      } catch(e) {}
    }
  }
  return JSON.stringify(result.slice(0,15));
})()
""")
print("[Cheetah API]", r[:500] if r else 'empty')

# 2. 找 window 上所有带 $ 或 _ 开头的内部对象
r = cdp(s, """
(function() {
  var result = [];
  for (var k in window) {
    if ((k.startsWith('$') || k.startsWith('_') || k.startsWith('cheetah')) &&
        k !== '$_' && k !== '$' && k !== '_') {
      try {
        var v = window[k];
        if (typeof v === 'object' || typeof v === 'function') {
          result.push({name: k, type: typeof v, keys: typeof v === 'object' && v !== null ? Object.keys(v).slice(0,10).join(',') : ''});
        }
      } catch(e) {}
    }
  }
  return JSON.stringify(result.slice(0,20));
})()
""")
print("[$/_对象]", r[:500] if r else 'empty')

# 3. 找封面上传相关的 Cheetah 实例数据
r = cdp(s, """
(function() {
  // 找 cheetah-form-item-co 下所有带 upload/cover 的属性
  var all = document.querySelectorAll('.cheetah-form-item-co');
  var result = [];
  for (var el of all) {
    var keys = Object.keys(el);
    for (var k of keys) {
      if (k.indexOf('upload') > -1 || k.indexOf('cover') > -1 || k.indexOf('image') > -1) {
        try {
          var v = el[k];
          result.push({el: 'cheetah-form-item-co', key: k, val: typeof v === 'object' ? JSON.stringify(v).substring(0,60) : String(v).substring(0,40)});
        } catch(e) {}
      }
    }
  }
  return JSON.stringify(result);
})()
""")
print("[Cheetah表单]", r[:400] if r else 'empty')

# 4. 找 data-* 属性
r = cdp(s, """
(function() {
  var all = document.querySelectorAll('[data-upload], [data-cover], [data-image], [data-cheetah]');
  var result = [];
  for (var el of all) {
    var attrs = {};
    for (var attr of el.attributes) {
      if (attr.name.indexOf('data-') === 0) {
        attrs[attr.name] = attr.value.substring(0,30);
      }
    }
    result.push({tag: el.tagName, attrs: attrs, class: el.className.substring(0,30)});
  }
  return JSON.stringify(result);
})()
""")
print("[data属性]", r[:400] if r else 'empty')

# 5. 直接触发 file input change 事件
print("\n[触发 file input change...]")
cdp(s, "window.__COVER_B64__='%s'" % IMG_B64[:50000], timeout=5)
r = cdp(s, """
(function() {
  var inputs = document.querySelectorAll('input[type=file]');
  var result = [];
  for (var inp of inputs) {
    if (inp.accept && inp.accept.indexOf('video') > -1) {
      // 这是视频上传，不处理
      result.push('video_skip');
      continue;
    }
    var parent = inp.parentElement;
    if (parent && parent.className && parent.className.indexOf('editor-outter') > -1) {
      // 找图片
      var b64 = window.__COVER_B64__ || '';
      if (!b64) { result.push('no_b64'); continue; }
      var byteString = atob(b64);
      var ab = new ArrayBuffer(byteString.length);
      var ia = new Uint8Array(ab);
      for (var i = 0; i < byteString.length; i++) ia[i] = byteString.charCodeAt(i);
      var blob = new Blob([ab], {type: 'image/jpeg'});
      var file = new File([blob], 'cover.jpg', {type: 'image/jpeg'});
      // 检查 accept
      result.push({accept: inp.accept, parent: parent.className, id: inp.id, name: inp.name});
    }
  }
  return JSON.stringify(result);
})()
""")
print("file inputs:", r[:300] if r else 'empty')

s.close()
