904118851 il y a 7 mois
Parent
commit
9cb4c84741

BIN
1.jpg


BIN
2.jpg


+ 1 - 0
2_PRODUCT_FACTORY/hy_batch_factory.js

@@ -143,6 +143,7 @@ async function processCreateTask(){
         if(task_queue.length>0){
             let task_queue_item = task_queue.pop()
             result = task_queue_item.result
+            console.log("result:",result)
             let other_book = await other_book_controllers.getData({product_id:task_queue_item.result.data.book_id})
             if(other_book.success){
                 await filter_data_controllers.updateFilterData({id:result.data.id},{status:2,book_id:other_book.data.product_id,book_name:other_book.data.product_name,material_sync_status:2})

+ 86 - 0
5_CREATE_LINK_FACTORY/qm_new_create_link.js

@@ -0,0 +1,86 @@
+
+const fetch = require('node-fetch'); // Node.js 18以下版本需要安装 node-fetch
+const tools = require('../tools');
+const helper = require('../src/helper');
+const config = require('../etc/config.json')
+const CMD = {}
+CMD.runTask = async function (data,main_info,PlatformInfo,call_back) {
+    let timestamp = helper.getCurrentUnixTimestamp()
+    let tg_link_config = JSON.parse(main_info.tg_link_config)
+    let chongzhi_id = tg_link_config['chongzhi_id']
+    let huichuan_id = tg_link_config['huichuan_id']
+    let f_chongzhi_id = tg_link_config['f_chongzhi_id']
+    let chongzhi_list = JSON.parse(PlatformInfo.chongzhi)
+    let huichuan_list = JSON.parse(PlatformInfo.huichuan)
+    let f_chongzhi_list = JSON.parse(PlatformInfo.f_chongzhi)
+    let recharge_template_id = ""
+    let f_recharge_template_id = ""
+    let call_back_template_id = ""
+
+    for (let index = 0; index < chongzhi_list.length; index++) {
+        const cz_obj = chongzhi_list[index];
+        if(cz_obj.id==chongzhi_id){
+          recharge_template_id = cz_obj.value
+          break
+        }
+    }
+
+    for (let index = 0; index < huichuan_list.length; index++) {
+        const hc_obj = huichuan_list[index];
+        if(hc_obj.id==huichuan_id){
+          call_back_template_id = hc_obj.value
+          break
+        }
+    }
+
+    for (let index = 0; index < f_chongzhi_list.length; index++) {
+        const cz_obj = f_chongzhi_list[index];
+        if(cz_obj.id==f_chongzhi_id){
+            f_recharge_template_id = cz_obj.value
+          break
+        }
+    }
+
+    let param_list = main_info.qm_id.split(',')
+    let app_external_id = param_list[1]
+    let target_id = param_list[0]
+
+    let postData = {
+        admin_account_name:"zhuoyue",
+        account_id:target_id,
+        project:PlatformInfo.mini_program_platform_id==config.wx?8:6,     // 6 抖音小程序  8 微信小程序
+        appid:main_info.app_id,
+        book_id:data.product_id,
+        chapter_num:1,
+        name:data.product_name,
+        media_id: '1', //1  巨量 2 广点通 3 百度 4 微博 5 B站
+        postback_rule_id: call_back_template_id, //# 回传规则 value
+        first_panel_id:recharge_template_id, //首充模板id
+        repeated_panel_id:f_recharge_template_id, //# 复充模板id
+    }
+    
+    console.log("postData:",postData)
+    
+    try{
+        let client = tools.getOneNewClinet()
+        let response =  await client.post(config.qimao_config.new_create_link_host,postData)
+        if(response.code!=0){
+            throw response
+        }
+        let n_data = response.data
+        let promotion_id = n_data.id
+        let promotion_info = n_data.link
+        let t_params = promotion_info.split('?')
+        let start_page = t_params[0]
+        let start_param = t_params[1]
+        data.start_page = start_page
+        data.start_param = start_param
+        data.promotion_id = promotion_id
+        call_back(data,null)
+    } catch (error) {
+        call_back(data,error)
+        console.error('请求错误:', error);
+    }
+}
+
+module.exports = CMD;

+ 158 - 50
5_CREATE_LINK_FACTORY/yw_create_link.js

@@ -5,6 +5,8 @@ const redis_help = require('../src/use_redis');
 const CMD = {}
 CMD.get_promotion_id_by_name = async function(name,yw_id) {
     try {
+        let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
+        let timestamp = helper.getCurrentUnixTimestamp()
         await require('../src/api/yw/switchApp').switchApp(yw_id)
         const response =  await fetch(`https://open.yuewen.com/api/miniappspread/getPromotionList?recycle=0&startdate=&enddate=&name=${name}&id=&content_type=0&page=1&channeltype=1&pagename=`, {
             "headers": {
@@ -17,7 +19,7 @@ CMD.get_promotion_id_by_name = async function(name,yw_id) {
                 "sec-fetch-dest": "empty",
                 "sec-fetch-mode": "cors",
                 "sec-fetch-site": "same-origin",
-                "cookie": "Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=bb27eaeca83cc7d957c47178eb9e6643; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=1",
+                "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=${timestamp}; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=1`,
                 "Referer": "https://open.yuewen.com/new/library",
                 "Referrer-Policy": "strict-origin-when-cross-origin"
             },
@@ -31,16 +33,98 @@ CMD.get_promotion_id_by_name = async function(name,yw_id) {
             throw data
         }
         
-        console.log('响应状态:', response.status);
-        console.log('响应数据:', data);
+        console.log('get_promotion_id_by_name::响应状态:', response.status);
+        console.log('get_promotion_id_by_name::响应数据:', data);
         return data.data.list[0];
     } catch (error) {
-        console.error('请求错误:', error);
+        console.error('get_promotion_id_by_name::请求错误:', error);
         return null
     }
 }
+
+CMD.test = async function() {
+    // 设置请求头
+    const headers = {
+        "accept": "application/json, text/plain, */*",
+        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+        "content-type": "application/json",
+        "priority": "u=1, i",
+        "sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
+        "sec-ch-ua-mobile": "?0",
+        "sec-ch-ua-platform": "\"Windows\"",
+        "sec-fetch-dest": "empty",
+        "sec-fetch-mode": "cors",
+        "sec-fetch-site": "same-origin",
+        "cookie": "Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=xKm-Q0k0vYm1SvdsRLP_kXsG; OPENSESSID=e055148579455596ff9d10d1b2c72024; yw_open_token=6787602677bbd; is_read_notice=6787602677bbd; sidebarStatus=0",
+        "Referer": "https://open.yuewen.com/new/library",
+        "Referrer-Policy": "strict-origin-when-cross-origin"
+    };
+
+    // 设置请求体
+    const requestBody = {
+        "cost": 0,
+        "name": "ceshi2222",
+        "cbid": "30554680307186706",
+        "ccid": "82019595711479505",
+        "page_name": "《渣男犯了错》第1章 01",
+        "channel_charge_setting": {
+            "id": 478,
+            "name": "29.9元",
+            "tenantId": 80091658,
+            "create_time": 1736829123000,
+            "update_time": 1736829123000,
+            "creator": "zyw****4013@163.com",
+            "updater": "zyw****4013@163.com",
+            "details": [
+                // VIP月度会员
+                {
+                    "vip_type": 1,
+                    "origin": 4485,
+                    "price": 2990,
+                    "gift": 0,
+                    "charge_desc": "1个月会员",
+                    "gift_desc": "仅0.96元/天",
+                    "bg_color": 0,
+                    "tag_color": 0,
+                    "tag_txt": "",
+                    "tag_type": 0,
+                    "tag_position": 0,
+                    "pay_id": 1,
+                    "first_charge": 0,
+                    "vip_charge_setting": {
+                        "type": 2,
+                        "dprice": 96,
+                        "quantity": 31,
+                        "product_id": "com.miniappvip.month.31days",
+                        "label_id": 0,
+                        "user_filter": 0,
+                        "rule_id": 0,
+                        "first_period_conf": []
+                    },
+                    "charge_setting_type": 1
+                },
+                // 其他会员配置...
+            ]
+        },
+        "backup_book_status": 2,
+        "channel_type": 1,
+        "force_style": "1"
+    };
+
+    // 发起请求
+    let response = await fetch("https://open.yuewen.com/api/miniappspread/addH5Spread", {
+        method: "POST",
+        headers: headers,
+        body: JSON.stringify(requestBody)
+    });
+
+    console.log("response:",response)
+}
 CMD.runTask = async function(t_data,main_info,PlatformInfo,call_back){
     try{
+        let chapter_info = await require('../src/api/yw/get_book_tg_chapter_id').get_book_tg_chapter_id(t_data.product_id)
+        console.log("main_info.yw_id:",main_info.yw_id)
+        console.log("chapter_info:",chapter_info)
         await require('../src/api/yw/switchApp').switchApp(main_info.yw_id)
         let timestamp = helper.getCurrentUnixTimestamp()
         let tg_link_config = JSON.parse(main_info.tg_link_config)
@@ -56,60 +140,84 @@ CMD.runTask = async function(t_data,main_info,PlatformInfo,call_back){
             }
         }
 
-        let chapter_info = await require('../src/api/yw/get_book_tg_chapter_id').get_book_tg_chapter_id(t_data.product_id)
         if(chapter_info==null){
             throw {"error_info":"get_book_tg_chapter_id error!"}
         }
         let promotion_name = `${t_data.product_name}_${timestamp}`
-        let postData = {
-            cost:"0",
-            name:promotion_name,
-            cbid:t_data.product_id,
-            ccid:chapter_info.cbid,
-            page_name:`《${t_data.product_name}》第1章`,
-            channel_charge_setting:channel_charge_setting,
-            backup_book_status:"2",
-            channel_type:"1",
-            force_style:"1"
-        }
+        let create_time = Date.now()
+        // let postData = {
+        //     cost:"0",
+        //     name:promotion_name,
+        //     cbid:t_data.product_id,
+        //     ccid:chapter_info.ccid,
+        //     page_name:`《${t_data.product_name}》第1章`,
+        //     channel_charge_setting:channel_charge_setting,
+        //     backup_book_status:"2",
+        //     channel_type:"1",
+        //     force_style:"1"
+        // }
         let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
-        const response =   await fetch(`https://open.yuewen.com/api/miniappspread/addH5Spread`, {
-            "headers": {
-                "accept": "application/json, text/plain, */*",
-                "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
-                "priority": "u=1, i",
-                "sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
-                "sec-ch-ua-mobile": "?0",
-                "sec-ch-ua-platform": "\"Windows\"",
-                "sec-fetch-dest": "empty",
-                "sec-fetch-mode": "cors",
-                "sec-fetch-site": "same-origin",
-                "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=0`,
-                "Referer": "https://open.yuewen.com/new/library",
-                "Referrer-Policy": "strict-origin-when-cross-origin"
+        const headers = {
+            "accept": "application/json, text/plain, */*",
+            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+            "content-type": "application/json",
+            "priority": "u=1, i",
+            "sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
+            "sec-ch-ua-mobile": "?0",
+            "sec-ch-ua-platform": "\"Windows\"",
+            "sec-fetch-dest": "empty",
+            "sec-fetch-mode": "cors",
+            "sec-fetch-site": "same-origin",
+            "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=xKm-Q0k0vYm1SvdsRLP_kXsG; OPENSESSID=${OPENSESSID}; yw_open_token=6787602677bbd; is_read_notice=6787602677bbd; sidebarStatus=0`,
+            "Referer": "https://open.yuewen.com/new/library",
+            "Referrer-Policy": "strict-origin-when-cross-origin"
+        };
+        let postData = {
+            "cost": 0,
+            "name": promotion_name,
+            "cbid": t_data.product_id,
+            "ccid": chapter_info.ccid,
+            "page_name": `《${t_data.product_name}》第1章 01`,
+            "channel_charge_setting": {
+                "id": channel_charge_setting.id,
+                "name": channel_charge_setting.name,
+                "tenantId": channel_charge_setting.tenantId,
+                "create_time": create_time,
+                "update_time": create_time,
+                "creator": "zyw****4013@163.com",
+                "updater": "zyw****4013@163.com",
+                "details":channel_charge_setting.details
             },
-                "body": postData,
-                "method": "POST"
-            });
-    
-            const data = await response.json();
-    
-            if(data.code!=0){
-                throw null
-            }
-            let promotion_info = await CMD.get_promotion_id_by_name(promotion_name,main_info.yw_id)
-            let t_params = promotion_info.path.split('?')
-            let start_page = t_params[0]
-            let start_param = t_params[1]
-            t_data.promotion_id = promotion_info.id
-            t_data.start_page = start_page
-            t_data.start_param = start_param
-            console.log('响应状态:', response.status);
-            console.log('响应数据:', data);
-            call_back(t_data,null)
+            "backup_book_status": 2,
+            "channel_type": 1,
+            "force_style": "1"
+        };
+        console.log("postData:",postData)
+
+        let response = await fetch("https://open.yuewen.com/api/miniappspread/addH5Spread", {
+            method: "POST",
+            headers: headers,
+            body: JSON.stringify(postData)
+        });
+
+        const data = await response.json();
 
+        if(data.code!=0){
+            throw data
+        }
+        let promotion_info = await CMD.get_promotion_id_by_name(promotion_name,main_info.yw_id)
+        let t_params = promotion_info.path.split('?')
+        let start_page = t_params[0]
+        let start_param = t_params[1]
+        t_data.promotion_id = promotion_info.id
+        t_data.start_page = start_page
+        t_data.start_param = start_param
+        console.log('CMD.runTask::响应状态:', response.status);
+        console.log('CMD.runTask:响应数据:', data);
+        console.log('t_data:',t_data)
+        call_back(t_data,null)
     }catch(error){
-        console.error('请求错误:', error);
+        console.error('CMD.runTask:请求错误:', error);
         call_back(t_data,error)
         return null;
     }

+ 2 - 2
5_CREATE_LINK_FACTORY/yw_create_link_factory.js

@@ -150,8 +150,8 @@ async function processTask(){
                 yw_create_link_task.PlatformInfo,finish_call_back)
         }
     }catch(e){
-        console.log("qm_create_link_factory error:",e)
-        finish_call_back(null,{"MESSAGE":"qm_create_link_factory error:"})
+        console.log("yw_create_link_factory error:",e)
+        finish_call_back(null,{"MESSAGE":"yw_create_link_factory error:"})
     } finally{
         global.setTimeout(processTask,time_count)
     }

+ 27 - 8
MESSAGE_DISPATCH/ocr_script.py

@@ -42,7 +42,16 @@ class MyRequestHandler(BaseHTTPRequestHandler):
             elif cmd == "chapterSpread":
                 if not all(k in data for k in ['cbid', 'OPENSESSID']):
                     raise ValueError("Missing required parameters for chapterSpread")
-                response = chapterSpread(data)
+                response = {
+                    "message": "Data received successfully",
+                    "received_data": temp_chapterSparead(data),
+                }
+                # chapterSpread(data)
+                response_str = json.dumps(response)
+                self.send_response(200)
+                self.send_header('Content-type', 'application/json')
+                self.end_headers()
+                self.wfile.write(response_str.encode('utf-8'))
             elif cmd == "get_fq_book":
                 key = data.get('key')
                 response = {
@@ -159,28 +168,38 @@ def getFqBook( key,post_data=None):
             'http_code': 0
         }
 
-def chapterSpread( data):
+def temp_chapterSparead(data):
     cookies = {
         'Hm_lvt_990f9ab9737a266517417cc2949bb3f4': '1736394515',
         'csrfToken': 'vN8OkvTZZfzerTHhodh7rc81',
-        'OPENSESSID': 'ada39ae2c1286d1be3bd32e300951fff',
+        'OPENSESSID': data['OPENSESSID'],
         'yw_open_token': '6785d8c2ec046',
         'is_read_notice': '6785d8c2ec046',
         'sidebarStatus': '0',
     }
 
+    print(cookies)
     headers = {
         'authority': 'open.yuewen.com',
         'accept': 'application/json, text/plain, */*',
-        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
+        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
+        'priority': 'u=1, i',
+        'referer': 'https://open.yuewen.com/new/library',
+        'sec-ch-ua': '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
+        'sec-ch-ua-mobile': '?0',
+        'sec-ch-ua-platform': '"Windows"',
+        'sec-fetch-dest': 'empty',
+        'sec-fetch-mode': 'cors',
+        'sec-fetch-site': 'same-origin',
+        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0'
     }
 
     url = 'https://open.yuewen.com/api/wechatspread/chapterSpread'
-    params = {'cbid': data['cbid']}
+    params = {
+        'cbid': data['cbid']
+    }
+    print(params)
     response = requests.get(url, params=params, cookies=cookies, headers=headers)
-    print(cookies)
-    print(data['cbid'])
-    print(response.json())
     return response.json()
 
 if __name__ == "__main__":

+ 1 - 1
MESSAGE_DISPATCH/run_py.sh

@@ -1,3 +1,3 @@
 lsof -i :8080 | grep LISTEN | awk '{print $2}' | xargs sudo kill -9
 sleep 1
- python3.8 ocr_script.py
+nohup python3.8 ocr_script.py

BIN
dump.rdb


+ 1 - 0
etc/config.json

@@ -44,6 +44,7 @@
         "access_key":"09ba094d2f70e0e5bc340cca365fabe3",
         "secret_key":"36bb8183bf00a78dd55422156ee5b2dc",
         "Appid":"tt79e30f5ee6d455b601",
+        "new_create_link_host":"https://new-media-mapi.qimao.com/mapi/v1/promotion-link/create",
         "create_link_host":"https://new-media-mapi.qimao.com/mapi/v1/promotion-link/list", 
         "login_host":"https://new-media-fx.qimao.com/api/account/login?env=&qm_csrf_backend=undefined&t=",
         "callbacklist_hots":"https://new-media-fx.qimao.com/api/postback/rule/list?page=1&page_size=50&env=&t=",

+ 591 - 0
geetest_crack.py

@@ -0,0 +1,591 @@
+import os
+import time
+import logging
+import signal
+import subprocess
+import cv2
+import numpy as np
+from PIL import Image
+import io
+import base64
+import random
+from selenium import webdriver
+from selenium.webdriver.firefox.options import Options
+from selenium.webdriver.firefox.service import Service
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.action_chains import ActionChains
+from contextlib import contextmanager
+
+# 配置日志
+logging.basicConfig(
+    level=logging.INFO,
+    format='%(asctime)s - %(levelname)s - %(message)s'
+)
+logger = logging.getLogger(__name__)
+
+class TimeoutException(Exception):
+    pass
+
+@contextmanager
+def time_limit(seconds):
+    def signal_handler(signum, frame):
+        raise TimeoutException("Timed out!")
+    signal.signal(signal.SIGALRM, signal_handler)
+    signal.alarm(seconds)
+    try:
+        yield
+    finally:
+        signal.alarm(0)
+
+class GeetestCracker:
+    def __init__(self):
+        self.driver = None
+        self.wait = None
+        logger.info("初始化 GeetestCracker")
+
+    def cleanup_processes(self):
+        """清理残留进程"""
+        try:
+            subprocess.run(['pkill', '-f', 'firefox'], stderr=subprocess.DEVNULL)
+            subprocess.run(['pkill', '-f', 'geckodriver'], stderr=subprocess.DEVNULL)
+            time.sleep(2)
+            logger.info("清理残留进程完成")
+        except Exception as e:
+            logger.error(f"清理进程时出错: {str(e)}")
+
+    def setup_driver(self):
+        """配置并初始化 WebDriver"""
+        try:
+            logger.info("开始设置浏览器驱动")
+            
+            # 首先清理可能的残留进程
+            self.cleanup_processes()
+            
+            # 检查 geckodriver
+            from shutil import which
+            geckodriver_path = which('geckodriver')
+            
+            if not geckodriver_path:
+                logger.error("未找到 geckodriver")
+                return False
+                
+            logger.info(f"找到 geckodriver: {geckodriver_path}")
+            
+            # Firefox 配置 - 修改配置以提高稳定性
+            options = Options()
+            
+            # 核心配置
+            options.set_preference('marionette', True)
+            options.set_preference('marionette.port', 2828)  # 固定端口
+            options.set_preference('network.http.connection-timeout', 10000)
+            options.set_preference('network.http.response.timeout', 10000)
+            
+            # 禁用 JavaScript JIT
+            options.set_preference('javascript.options.ion', False)
+            options.set_preference('javascript.options.baselinejit', False)
+            
+            # 禁用硬件加速
+            options.set_preference('layers.acceleration.disabled', True)
+            
+            # 禁用不必要的功能
+            options.set_preference('browser.cache.disk.enable', False)
+            options.set_preference('browser.cache.memory.enable', False)
+            options.set_preference('browser.cache.offline.enable', False)
+            options.set_preference('network.http.use-cache', False)
+            options.set_preference('browser.tabs.remote.autostart', False)
+            options.set_preference('browser.tabs.remote.autostart.2', False)
+            options.set_preference('dom.ipc.processCount', 1)
+            options.set_preference('browser.sessionstore.resume_from_crash', False)
+            
+            # 添加必要的参数
+            options.add_argument('--headless')
+            options.add_argument('--no-sandbox')
+            options.add_argument('--disable-dev-shm-usage')
+            options.add_argument('--disable-gpu')
+            options.add_argument('--disable-extensions')
+            options.add_argument('--disable-infobars')
+            options.add_argument('--disable-notifications')
+            options.add_argument('--window-size=1280,800')
+            
+            logger.info("创建 WebDriver 实例")
+            
+            # 使用临时目录
+            import tempfile
+            temp_dir = tempfile.mkdtemp()
+            
+            # Firefox 临时配置目录
+            options.set_preference('profile', temp_dir)
+            
+            # 创建 Service 对象,添加更多日志选项
+            service = Service(
+                geckodriver_path,
+                log_output=os.path.join(temp_dir, 'geckodriver.log'),
+                service_args=[
+                    '--log', 'trace',
+                    '--marionette-port', '2828'
+                ]
+            )
+            
+            # 设置超时限制并重试
+            max_attempts = 3
+            for attempt in range(max_attempts):
+                try:
+                    logger.info(f"尝试创建 WebDriver 实例 (尝试 {attempt + 1}/{max_attempts})")
+                    
+                    # 设置环境变量
+                    os.environ['MOZ_HEADLESS'] = '1'
+                    os.environ['DISPLAY'] = ':99'
+                    
+                    # 创建虚拟显示
+                    try:
+                        subprocess.run(['Xvfb', ':99', '-screen', '0', '1280x800x24'], 
+                                    start_new_session=True,
+                                    stdout=subprocess.DEVNULL,
+                                    stderr=subprocess.DEVNULL)
+                    except:
+                        logger.warning("Xvfb 启动失败,继续尝试")
+                    
+                    # 设置严格的超时
+                    with time_limit(20):  # 减少超时时间
+                        self.driver = webdriver.Firefox(
+                            service=service,
+                            options=options
+                        )
+                        
+                        # 设置页面加载超时
+                        self.driver.set_page_load_timeout(10)
+                        self.driver.set_script_timeout(10)
+                        self.wait = WebDriverWait(self.driver, 10)
+                        
+                        # 测试连接
+                        logger.info("测试浏览器连接")
+                        self.driver.get('about:blank')
+                        
+                        logger.info("浏览器驱动初始化成功")
+                        return True
+                        
+                except TimeoutException:
+                    logger.error(f"第 {attempt + 1} 次尝试超时")
+                except Exception as e:
+                    logger.error(f"第 {attempt + 1} 次尝试失败: {str(e)}")
+                
+                # 清理资源
+                self.cleanup_driver()
+                self.cleanup_processes()
+                
+                if attempt < max_attempts - 1:
+                    logger.info("等待后重试...")
+                    time.sleep(5)
+                else:
+                    raise Exception("在多次尝试后仍然失败")
+        
+        except Exception as e:
+            logger.error(f"浏览器驱动初始化失败: {str(e)}")
+            self.cleanup_driver()
+            return False
+            
+        finally:
+            # 清理临时目录
+            try:
+                import shutil
+                shutil.rmtree(temp_dir, ignore_errors=True)
+            except:
+                pass
+            
+            # 停止虚拟显示
+            try:
+                subprocess.run(['pkill', 'Xvfb'], 
+                            stdout=subprocess.DEVNULL,
+                            stderr=subprocess.DEVNULL)
+            except:
+                pass
+
+    def cleanup_processes(self):
+        """更彻底地清理残留进程"""
+        try:
+            # 使用 pkill 清理进程
+            commands = [
+                ['pkill', '-f', 'firefox'],
+                ['pkill', '-f', 'geckodriver'],
+                ['pkill', '-f', 'Xvfb'],
+                ['killall', 'firefox'],
+                ['killall', 'geckodriver'],
+                ['killall', 'Xvfb']
+            ]
+            
+            for cmd in commands:
+                try:
+                    subprocess.run(cmd, 
+                                stdout=subprocess.DEVNULL,
+                                stderr=subprocess.DEVNULL)
+                except:
+                    continue
+            
+            # 使用 ps 查找并强制终止进程
+            try:
+                ps_output = subprocess.check_output(['ps', 'aux']).decode()
+                for line in ps_output.split('\n'):
+                    if 'firefox' in line or 'geckodriver' in line or 'Xvfb' in line:
+                        try:
+                            pid = int(line.split()[1])
+                            os.kill(pid, signal.SIGKILL)
+                        except:
+                            continue
+            except:
+                pass
+                
+            time.sleep(2)
+            logger.info("清理残留进程完成")
+        except Exception as e:
+            logger.error(f"清理进程时出错: {str(e)}")
+
+    def navigate_to_page(self):
+        """导航到目标页面"""
+        try:
+            logger.info("正在访问目标网页")
+            
+            max_attempts = 3
+            for attempt in range(max_attempts):
+                try:
+                    logger.info(f"尝试访问页面 (尝试 {attempt + 1}/{max_attempts})")
+                    
+                    # 增加页面加载超时时间
+                    self.driver.set_page_load_timeout(30)
+                    
+                    # 直接访问目标验证码页面
+                    target_url = 'https://open.yuewen.com/'
+                    logger.info(f"访问目标URL: {target_url}")
+                    self.driver.get(target_url)
+                    
+                    # 等待页面加载完成
+                    logger.info("等待页面加载")
+                    WebDriverWait(self.driver, 30).until(
+                        lambda driver: driver.execute_script("return document.readyState") == "complete"
+                    )
+                    
+                    # 检查页面是否正确加载
+                    try:
+                        # 验证是否存在验证码相关元素
+                        slide_button = WebDriverWait(self.driver, 10).until(
+                            EC.presence_of_element_located((By.CLASS_NAME, "geetest_slider_button"))
+                        )
+                        
+                        if not slide_button:
+                            raise Exception("未找到滑块验证码元素")
+                        
+                        logger.info("验证码页面加载成功")
+                        return True
+                        
+                    except Exception as e:
+                        logger.error(f"验证码元素检查失败: {str(e)}")
+                        raise
+                    
+                except Exception as e:
+                    logger.error(f"第 {attempt + 1} 次尝试失败: {str(e)}")
+                    if attempt < max_attempts - 1:
+                        logger.info("等待后重试...")
+                        
+                        # 重置浏览器状态
+                        try:
+                            self.driver.execute_script("""
+                                window.stop();
+                                window.location.href = 'about:blank';
+                            """)
+                        except:
+                            pass
+                        
+                        time.sleep(5)
+                    else:
+                        raise Exception("页面访问在多次尝试后仍然失败")
+                        
+        except Exception as e:
+            logger.error(f"页面访问失败: {str(e)}")
+            return False
+        
+        finally:
+            # 重置页面加载超时为默认值
+            try:
+                self.driver.set_page_load_timeout(30)
+            except:
+                pass
+
+
+
+    def setup_browser_config(self):
+        """配置浏览器网络设置"""
+        try:
+            # 配置网络设置
+            self.driver.execute_script("""
+                navigator.connection = {
+                    effectiveType: '4g',
+                    rtt: 50,
+                    downlink: 10,
+                    saveData: false
+                };
+            """)
+            
+            # 设置自定义请求头
+            self.driver.execute_cdp_cmd('Network.setUserAgentOverride', {
+                "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
+            })
+            
+            # 启用网络监控
+            self.driver.execute_cdp_cmd('Network.enable', {})
+            
+            # 设置网络条件
+            self.driver.execute_cdp_cmd('Network.emulateNetworkConditions', {
+                'offline': False,
+                'latency': 20,  # 延迟时间(毫秒)
+                'downloadThroughput': 780 * 1024 / 8,  # 下载速度(字节/秒)
+                'uploadThroughput': 330 * 1024 / 8,  # 上传速度(字节/秒)
+                'connectionType': 'wifi'
+            })
+            
+            return True
+        except Exception as e:
+            logger.error(f"配置浏览器网络设置失败: {str(e)}")
+            return False
+    def get_slider(self):
+        """获取滑块元素"""
+        try:
+            logger.info("寻找滑块元素")
+            
+            # 尝试多种定位方式
+            selectors = [
+                (By.CLASS_NAME, "gt_slider_knob"),
+                (By.CLASS_NAME, "geetest_slider_button"),
+                (By.CLASS_NAME, "gt_slider_knob_new"),
+                (By.CSS_SELECTOR, ".gt_slider_knob"),
+                (By.CSS_SELECTOR, ".geetest_slider_button"),
+                (By.XPATH, "//div[contains(@class, 'slider')]//div[contains(@class, 'knob')]")
+            ]
+            
+            # 等待任意一个元素出现
+            for selector in selectors:
+                try:
+                    logger.info(f"尝试使用选择器: {selector}")
+                    element = WebDriverWait(self.driver, 10).until(
+                        EC.presence_of_element_located(selector)
+                    )
+                    if element:
+                        logger.info(f"成功找到滑块元素: {selector}")
+                        return element
+                except:
+                    continue
+            
+            raise Exception("未能找到滑块元素")
+            
+        except Exception as e:
+            logger.error(f"获取滑块元素失败: {str(e)}")
+            return None
+
+    def get_slider_background(self):
+        """获取背景图片"""
+        try:
+            # 等待背景图片加载
+            background = WebDriverWait(self.driver, 10).until(
+                EC.presence_of_element_located((By.CLASS_NAME, "gt_box"))
+            )
+            # 获取背景图片的base64数据
+            canvas = self.driver.execute_script(
+                "return document.getElementsByClassName('gt_box')[0].toDataURL('image/png')"
+            )
+            # 转换base64为图片
+            canvas = canvas.split(',')[1]
+            image_data = base64.b64decode(canvas)
+            image = Image.open(io.BytesIO(image_data))
+            return image
+        except Exception as e:
+            logger.error(f"获取背景图片失败: {str(e)}")
+            return None
+
+    def get_slider_image(self):
+        """获取滑块图片"""
+        try:
+            # 等待滑块图片加载
+            slider = WebDriverWait(self.driver, 10).until(
+                EC.presence_of_element_located((By.CLASS_NAME, "gt_slice"))
+            )
+            # 获取滑块图片的base64数据
+            canvas = self.driver.execute_script(
+                "return document.getElementsByClassName('gt_slice')[0].toDataURL('image/png')"
+            )
+            # 转换base64为图片
+            canvas = canvas.split(',')[1]
+            image_data = base64.b64decode(canvas)
+            image = Image.open(io.BytesIO(image_data))
+            return image
+        except Exception as e:
+            logger.error(f"获取滑块图片失败: {str(e)}")
+            return None
+
+    def get_gap(self, bg_image, slider_image):
+        """计算滑块缺口位置"""
+        try:
+            # 转换图片格式
+            bg = cv2.cvtColor(np.array(bg_image), cv2.COLOR_RGB2BGR)
+            slider = cv2.cvtColor(np.array(slider_image), cv2.COLOR_RGB2BGR)
+            
+            # 计算差异
+            diff = cv2.absdiff(bg, slider)
+            mask = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
+            ret, mask = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)
+            
+            # 查找轮廓
+            contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+            
+            if contours:
+                # 获取最大轮廓
+                max_contour = max(contours, key=cv2.contourArea)
+                x, y, w, h = cv2.boundingRect(max_contour)
+                return x
+            return None
+        except Exception as e:
+            logger.error(f"计算缺口位置失败: {str(e)}")
+            return None
+
+    def generate_track(self, distance):
+        """生成移动轨迹"""
+        tracks = []
+        current = 0
+        mid = distance * 3 / 4
+        t = 0.2
+        v = 0
+        
+        while current < distance:
+            if current < mid:
+                a = 2
+            else:
+                a = -3
+            v0 = v
+            v = v0 + a * t
+            move = v0 * t + 1 / 2 * a * t * t
+            current += move
+            tracks.append(round(move))
+        
+        # 微调
+        while sum(tracks) > distance:
+            tracks[-1] -= 1
+        while sum(tracks) < distance:
+            tracks.append(1)
+            
+        # 添加回退
+        tracks.extend([-1, -1, -2, -2, -1, -1])
+        return tracks
+
+    def move_slider(self, slider, tracks):
+        """移动滑块"""
+        try:
+            ActionChains(self.driver).click_and_hold(slider).perform()
+            for track in tracks:
+                ActionChains(self.driver).move_by_offset(track, random.randint(-1, 1)).perform()
+                time.sleep(random.uniform(0.01, 0.02))
+            time.sleep(0.5)
+            ActionChains(self.driver).release().perform()
+            return True
+        except Exception as e:
+            logger.error(f"移动滑块失败: {str(e)}")
+            return False
+
+    def crack_captcha(self):
+        """破解验证码主流程"""
+        try:
+            logger.info("开始破解验证码")
+            
+            # 获取滑块元素
+            slider = self.get_slider()
+            if not slider:
+                return False
+                
+            # 获取图片
+            bg_image = self.get_slider_background()
+            slider_image = self.get_slider_image()
+            if not bg_image or not slider_image:
+                return False
+                
+            # 计算缺口位置
+            gap = self.get_gap(bg_image, slider_image)
+            if not gap:
+                return False
+            logger.info(f"缺口位置: {gap}")
+            
+            # 生成轨迹
+            tracks = self.generate_track(gap)
+            logger.info(f"生成轨迹: {len(tracks)}个点")
+            
+            # 移动滑块
+            result = self.move_slider(slider, tracks)
+            if not result:
+                return False
+                
+            # 等待验证结果
+            time.sleep(2)
+            
+            # 检查是否验证成功
+            try:
+                success = WebDriverWait(self.driver, 5).until(
+                    EC.presence_of_element_located((By.CLASS_NAME, "gt_success"))
+                )
+                if success:
+                    logger.info("验证成功")
+                    return True
+            except:
+                logger.error("验证失败")
+                return False
+                
+        except Exception as e:
+            logger.error(f"验证码破解失败: {str(e)}")
+            return False
+
+    def cleanup_driver(self):
+        """清理 WebDriver 资源"""
+        if hasattr(self, 'driver') and self.driver:
+            try:
+                self.driver.quit()
+            except:
+                pass
+            finally:
+                self.driver = None
+
+    def run(self):
+        """运行主程序"""
+        try:
+            logger.info("开始破解验证码流程")
+            
+            # 初始化浏览器
+            if not self.setup_driver():
+                return False
+                
+            # 访问目标页面
+            if not self.navigate_to_page():
+                return False
+                
+            # 破解验证码
+            max_attempts = 3
+            for attempt in range(max_attempts):
+                logger.info(f"第 {attempt + 1} 次尝试破解验证码")
+                if self.crack_captcha():
+                    return True
+                time.sleep(2)
+                
+            return False
+            
+        except Exception as e:
+            logger.error(f"程序执行失败: {str(e)}")
+            return False
+            
+        finally:
+            logger.info("程序执行结束")
+            self.cleanup_driver()
+
+    def __del__(self):
+        """析构函数,确保资源被清理"""
+        self.cleanup_driver()
+        self.cleanup_processes()
+
+if __name__ == "__main__":
+    cracker = GeetestCracker()
+    result = cracker.run()
+    print("破解结果:", "成功" if result else "失败")

+ 0 - 411
logs/combined.log

@@ -1,411 +0,0 @@
-<<<<<<< HEAD
-2025-01-15T14:14:13: 
-2025-01-15T14:14:13: > heiyan@1.0.0 start
-2025-01-15T14:14:13: > node tg_factory_main.js
-2025-01-15T14:14:13: 
-2025-01-15T14:14:16: Connected to Redis
-2025-01-15T14:30:06: 
-2025-01-15T14:30:06: > heiyan@1.0.0 start
-2025-01-15T14:30:06: > node tg_factory_main.js
-2025-01-15T14:30:06: 
-2025-01-15T14:30:09: Connected to Redis
-2025-01-15T14:30:09: 请求错误: AxiosError: connect ECONNREFUSED 127.0.0.1:8080
-2025-01-15T14:30:09:     at AxiosError.from (/home/tg_factory/node_modules/axios/dist/node/axios.cjs:876:14)
-2025-01-15T14:30:09:     at RedirectableRequest.handleRequestError (/home/tg_factory/node_modules/axios/dist/node/axios.cjs:3156:25)
-2025-01-15T14:30:09:     at RedirectableRequest.emit (node:events:531:35)
-2025-01-15T14:30:09:     at eventHandlers.<computed> (/home/tg_factory/node_modules/follow-redirects/index.js:49:24)
-2025-01-15T14:30:09:     at ClientRequest.emit (node:events:519:28)
-2025-01-15T14:30:09:     at emitErrorEvent (node:_http_client:108:11)
-2025-01-15T14:30:09:     at Socket.socketErrorListener (node:_http_client:511:5)
-2025-01-15T14:30:09:     at Socket.emit (node:events:519:28)
-2025-01-15T14:30:09:     at emitErrorNT (node:internal/streams/destroy:169:8)
-2025-01-15T14:30:09:     at emitErrorCloseNT (node:internal/streams/destroy:128:3)
-2025-01-15T14:30:09:     at Axios.request (/home/tg_factory/node_modules/axios/dist/node/axios.cjs:4287:41)
-2025-01-15T14:30:09:     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
-2025-01-15T14:30:09:     at async CMD.get_book_tg_chapter_id (/home/tg_factory/src/api/yw/get_book_tg_chapter_id.js:26:26)
-2025-01-15T14:30:09:     at async /home/tg_factory/tg_factory_main.js:42:13 {
-2025-01-15T14:30:09:   port: 8080,
-2025-01-15T14:30:09:   address: '127.0.0.1',
-2025-01-15T14:30:09:   syscall: 'connect',
-2025-01-15T14:30:09:   code: 'ECONNREFUSED',
-2025-01-15T14:30:09:   errno: -111,
-2025-01-15T14:30:09:   config: {
-2025-01-15T14:30:09:     transitional: {
-2025-01-15T14:30:09:       silentJSONParsing: true,
-2025-01-15T14:30:09:       forcedJSONParsing: true,
-2025-01-15T14:30:09:       clarifyTimeoutError: false
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     adapter: [ 'xhr', 'http', 'fetch' ],
-2025-01-15T14:30:09:     transformRequest: [ [Function: transformRequest] ],
-2025-01-15T14:30:09:     transformResponse: [ [Function: transformResponse] ],
-2025-01-15T14:30:09:     timeout: 30000,
-2025-01-15T14:30:09:     xsrfCookieName: 'XSRF-TOKEN',
-2025-01-15T14:30:09:     xsrfHeaderName: 'X-XSRF-TOKEN',
-2025-01-15T14:30:09:     maxContentLength: -1,
-2025-01-15T14:30:09:     maxBodyLength: -1,
-2025-01-15T14:30:09:     env: { FormData: [Function], Blob: [class Blob] },
-2025-01-15T14:30:09:     validateStatus: [Function: validateStatus],
-2025-01-15T14:30:09:     headers: Object [AxiosHeaders] {
-2025-01-15T14:30:09:       Accept: 'application/json, text/plain, */*',
-2025-01-15T14:30:09:       'Content-Type': 'application/json',
-2025-01-15T14:30:09:       'User-Agent': 'axios/1.7.7',
-2025-01-15T14:30:09:       'Content-Length': '98',
-2025-01-15T14:30:09:       'Accept-Encoding': 'gzip, compress, deflate, br'
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     httpAgent: Agent {
-2025-01-15T14:30:09:       _events: [Object: null prototype],
-2025-01-15T14:30:09:       _eventsCount: 2,
-2025-01-15T14:30:09:       _maxListeners: undefined,
-2025-01-15T14:30:09:       defaultPort: 80,
-2025-01-15T14:30:09:       protocol: 'http:',
-2025-01-15T14:30:09:       options: [Object: null prototype],
-2025-01-15T14:30:09:       requests: [Object: null prototype] {},
-2025-01-15T14:30:09:       sockets: [Object: null prototype],
-2025-01-15T14:30:09:       freeSockets: [Object: null prototype] {},
-2025-01-15T14:30:09:       keepAliveMsecs: 1000,
-2025-01-15T14:30:09:       keepAlive: true,
-2025-01-15T14:30:09:       maxSockets: 5,
-2025-01-15T14:30:09:       maxFreeSockets: 2,
-2025-01-15T14:30:09:       scheduling: 'lifo',
-2025-01-15T14:30:09:       maxTotalSockets: Infinity,
-2025-01-15T14:30:09:       totalSocketCount: 1,
-2025-01-15T14:30:09:       [Symbol(shapeMode)]: false,
-2025-01-15T14:30:09:       [Symbol(kCapture)]: false
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     method: 'post',
-2025-01-15T14:30:09:     url: 'http://127.0.0.1:8080',
-2025-01-15T14:30:09:     data: '{"cmd":"chapterSpread","cbid":"20879682908817006","OPENSESSID":"ada39ae2c1286d1be3bd32e300951fff"}'
-2025-01-15T14:30:09:   },
-2025-01-15T14:30:09:   request: <ref *1> Writable {
-2025-01-15T14:30:09:     _events: {
-2025-01-15T14:30:09:       close: undefined,
-2025-01-15T14:30:09:       error: [Function: handleRequestError],
-2025-01-15T14:30:09:       prefinish: undefined,
-2025-01-15T14:30:09:       finish: undefined,
-2025-01-15T14:30:09:       drain: undefined,
-2025-01-15T14:30:09:       response: [Function: handleResponse],
-2025-01-15T14:30:09:       socket: [Array],
-2025-01-15T14:30:09:       timeout: undefined,
-2025-01-15T14:30:09:       abort: undefined
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     _writableState: WritableState {
-2025-01-15T14:30:09:       highWaterMark: 16384,
-2025-01-15T14:30:09:       length: 0,
-2025-01-15T14:30:09:       corked: 0,
-2025-01-15T14:30:09:       onwrite: [Function: bound onwrite],
-2025-01-15T14:30:09:       writelen: 0,
-2025-01-15T14:30:09:       bufferedIndex: 0,
-2025-01-15T14:30:09:       pendingcb: 0,
-2025-01-15T14:30:09:       [Symbol(kState)]: 17580812,
-2025-01-15T14:30:09:       [Symbol(kBufferedValue)]: null
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     _maxListeners: undefined,
-2025-01-15T14:30:09:     _options: {
-2025-01-15T14:30:09:       maxRedirects: 21,
-2025-01-15T14:30:09:       maxBodyLength: Infinity,
-2025-01-15T14:30:09:       protocol: 'http:',
-2025-01-15T14:30:09:       path: '/',
-2025-01-15T14:30:09:       method: 'POST',
-2025-01-15T14:30:09:       headers: [Object: null prototype],
-2025-01-15T14:30:09:       agents: [Object],
-2025-01-15T14:30:09:       auth: undefined,
-2025-01-15T14:30:09:       family: undefined,
-2025-01-15T14:30:09:       beforeRedirect: [Function: dispatchBeforeRedirect],
-2025-01-15T14:30:09:       beforeRedirects: [Object],
-2025-01-15T14:30:09:       hostname: '127.0.0.1',
-2025-01-15T14:30:09:       port: '8080',
-2025-01-15T14:30:09:       agent: [Agent],
-2025-01-15T14:30:09:       nativeProtocols: [Object],
-2025-01-15T14:30:09:       pathname: '/'
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     _ended: false,
-2025-01-15T14:30:09:     _ending: true,
-2025-01-15T14:30:09:     _redirectCount: 0,
-2025-01-15T14:30:09:     _redirects: [],
-2025-01-15T14:30:09:     _requestBodyLength: 98,
-2025-01-15T14:30:09:     _requestBodyBuffers: [ [Object] ],
-2025-01-15T14:30:09:     _eventsCount: 3,
-2025-01-15T14:30:09:     _onNativeResponse: [Function (anonymous)],
-2025-01-15T14:30:09:     _currentRequest: ClientRequest {
-2025-01-15T14:30:09:       _events: [Object: null prototype],
-2025-01-15T14:30:09:       _eventsCount: 7,
-2025-01-15T14:30:09:       _maxListeners: undefined,
-2025-01-15T14:30:09:       outputData: [],
-2025-01-15T14:30:09:       outputSize: 0,
-2025-01-15T14:30:09:       writable: true,
-2025-01-15T14:30:09:       destroyed: false,
-2025-01-15T14:30:09:       _last: false,
-2025-01-15T14:30:09:       chunkedEncoding: false,
-2025-01-15T14:30:09:       shouldKeepAlive: true,
-2025-01-15T14:30:09:       maxRequestsOnConnectionReached: false,
-2025-01-15T14:30:09:       _defaultKeepAlive: true,
-2025-01-15T14:30:09:       useChunkedEncodingByDefault: true,
-2025-01-15T14:30:09:       sendDate: false,
-2025-01-15T14:30:09:       _removedConnection: false,
-2025-01-15T14:30:09:       _removedContLen: false,
-2025-01-15T14:30:09:       _removedTE: false,
-2025-01-15T14:30:09:       strictContentLength: false,
-2025-01-15T14:30:09:       _contentLength: '98',
-2025-01-15T14:30:09:       _hasBody: true,
-2025-01-15T14:30:09:       _trailer: '',
-2025-01-15T14:30:09:       finished: false,
-2025-01-15T14:30:09:       _headerSent: true,
-2025-01-15T14:30:09:       _closed: false,
-2025-01-15T14:30:09:       socket: [Socket],
-2025-01-15T14:30:09:       _header: 'POST / HTTP/1.1\r\n' +
-2025-01-15T14:30:09:         'Accept: application/json, text/plain, */*\r\n' +
-2025-01-15T14:30:09:         'Content-Type: application/json\r\n' +
-2025-01-15T14:30:09:         'User-Agent: axios/1.7.7\r\n' +
-2025-01-15T14:30:09:         'Content-Length: 98\r\n' +
-2025-01-15T14:30:09:         'Accept-Encoding: gzip, compress, deflate, br\r\n' +
-2025-01-15T14:30:09:         'Host: 127.0.0.1:8080\r\n' +
-2025-01-15T14:30:09:         'Connection: keep-alive\r\n' +
-2025-01-15T14:30:09:         '\r\n',
-2025-01-15T14:30:09:       _keepAliveTimeout: 0,
-2025-01-15T14:30:09:       _onPendingData: [Function: nop],
-2025-01-15T14:30:09:       agent: [Agent],
-2025-01-15T14:30:09:       socketPath: undefined,
-2025-01-15T14:30:09:       method: 'POST',
-2025-01-15T14:30:09:       maxHeaderSize: undefined,
-2025-01-15T14:30:09:       insecureHTTPParser: undefined,
-2025-01-15T14:30:09:       joinDuplicateHeaders: undefined,
-2025-01-15T14:30:09:       path: '/',
-2025-01-15T14:30:09:       _ended: false,
-2025-01-15T14:30:09:       res: null,
-2025-01-15T14:30:09:       aborted: false,
-2025-01-15T14:30:09:       timeoutCb: [Function: emitRequestTimeout],
-2025-01-15T14:30:09:       upgradeOrConnect: false,
-2025-01-15T14:30:09:       parser: null,
-2025-01-15T14:30:09:       maxHeadersCount: null,
-2025-01-15T14:30:09:       reusedSocket: false,
-2025-01-15T14:30:09:       host: '127.0.0.1',
-2025-01-15T14:30:09:       protocol: 'http:',
-2025-01-15T14:30:09:       _redirectable: [Circular *1],
-2025-01-15T14:30:09:       [Symbol(shapeMode)]: false,
-2025-01-15T14:30:09:       [Symbol(kCapture)]: false,
-2025-01-15T14:30:09:       [Symbol(kBytesWritten)]: 0,
-2025-01-15T14:30:09:       [Symbol(kNeedDrain)]: false,
-2025-01-15T14:30:09:       [Symbol(corked)]: 0,
-2025-01-15T14:30:09:       [Symbol(kOutHeaders)]: [Object: null prototype],
-2025-01-15T14:30:09:       [Symbol(errored)]: null,
-2025-01-15T14:30:09:       [Symbol(kHighWaterMark)]: 16384,
-2025-01-15T14:30:09:       [Symbol(kRejectNonStandardBodyWrites)]: false,
-2025-01-15T14:30:09:       [Symbol(kUniqueHeaders)]: null
-2025-01-15T14:30:09:     },
-2025-01-15T14:30:09:     _currentUrl: 'http://127.0.0.1:8080/',
-2025-01-15T14:30:09:     _timeout: null,
-2025-01-15T14:30:09:     [Symbol(shapeMode)]: true,
-2025-01-15T14:30:09:     [Symbol(kCapture)]: false
-2025-01-15T14:30:09:   },
-2025-01-15T14:30:09:   cause: Error: connect ECONNREFUSED 127.0.0.1:8080
-2025-01-15T14:30:09:       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1607:16) {
-2025-01-15T14:30:09:     errno: -111,
-2025-01-15T14:30:09:     code: 'ECONNREFUSED',
-2025-01-15T14:30:09:     syscall: 'connect',
-2025-01-15T14:30:09:     address: '127.0.0.1',
-2025-01-15T14:30:09:     port: 8080
-2025-01-15T14:30:09:   }
-2025-01-15T14:30:09: }
-2025-01-15T14:32:20: 
-2025-01-15T14:32:20: > heiyan@1.0.0 start
-2025-01-15T14:32:20: > node tg_factory_main.js
-2025-01-15T14:32:20: 
-2025-01-15T14:32:21: Connected to Redis
-2025-01-15T14:32:21: 请求错误: AxiosError: socket hang up
-2025-01-15T14:32:21:     at AxiosError.from (/home/tg_factory/node_modules/axios/dist/node/axios.cjs:876:14)
-2025-01-15T14:32:21:     at RedirectableRequest.handleRequestError (/home/tg_factory/node_modules/axios/dist/node/axios.cjs:3156:25)
-2025-01-15T14:32:21:     at RedirectableRequest.emit (node:events:531:35)
-2025-01-15T14:32:21:     at eventHandlers.<computed> (/home/tg_factory/node_modules/follow-redirects/index.js:49:24)
-2025-01-15T14:32:21:     at ClientRequest.emit (node:events:519:28)
-2025-01-15T14:32:21:     at emitErrorEvent (node:_http_client:108:11)
-2025-01-15T14:32:21:     at Socket.socketOnEnd (node:_http_client:535:5)
-2025-01-15T14:32:21:     at Socket.emit (node:events:531:35)
-2025-01-15T14:32:21:     at endReadableNT (node:internal/streams/readable:1696:12)
-2025-01-15T14:32:21:     at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
-2025-01-15T14:32:21:     at Axios.request (/home/tg_factory/node_modules/axios/dist/node/axios.cjs:4287:41)
-2025-01-15T14:32:21:     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
-2025-01-15T14:32:21:     at async CMD.get_book_tg_chapter_id (/home/tg_factory/src/api/yw/get_book_tg_chapter_id.js:26:26)
-2025-01-15T14:32:21:     at async /home/tg_factory/tg_factory_main.js:42:13 {
-2025-01-15T14:32:21:   code: 'ECONNRESET',
-2025-01-15T14:32:21:   config: {
-2025-01-15T14:32:21:     transitional: {
-2025-01-15T14:32:21:       silentJSONParsing: true,
-2025-01-15T14:32:21:       forcedJSONParsing: true,
-2025-01-15T14:32:21:       clarifyTimeoutError: false
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     adapter: [ 'xhr', 'http', 'fetch' ],
-2025-01-15T14:32:21:     transformRequest: [ [Function: transformRequest] ],
-2025-01-15T14:32:21:     transformResponse: [ [Function: transformResponse] ],
-2025-01-15T14:32:21:     timeout: 30000,
-2025-01-15T14:32:21:     xsrfCookieName: 'XSRF-TOKEN',
-2025-01-15T14:32:21:     xsrfHeaderName: 'X-XSRF-TOKEN',
-2025-01-15T14:32:21:     maxContentLength: -1,
-2025-01-15T14:32:21:     maxBodyLength: -1,
-2025-01-15T14:32:21:     env: { FormData: [Function], Blob: [class Blob] },
-2025-01-15T14:32:21:     validateStatus: [Function: validateStatus],
-2025-01-15T14:32:21:     headers: Object [AxiosHeaders] {
-2025-01-15T14:32:21:       Accept: 'application/json, text/plain, */*',
-2025-01-15T14:32:21:       'Content-Type': 'application/json',
-2025-01-15T14:32:21:       'User-Agent': 'axios/1.7.7',
-2025-01-15T14:32:21:       'Content-Length': '98',
-2025-01-15T14:32:21:       'Accept-Encoding': 'gzip, compress, deflate, br'
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     httpAgent: Agent {
-2025-01-15T14:32:21:       _events: [Object: null prototype],
-2025-01-15T14:32:21:       _eventsCount: 2,
-2025-01-15T14:32:21:       _maxListeners: undefined,
-2025-01-15T14:32:21:       defaultPort: 80,
-2025-01-15T14:32:21:       protocol: 'http:',
-2025-01-15T14:32:21:       options: [Object: null prototype],
-2025-01-15T14:32:21:       requests: [Object: null prototype] {},
-2025-01-15T14:32:21:       sockets: [Object: null prototype],
-2025-01-15T14:32:21:       freeSockets: [Object: null prototype] {},
-2025-01-15T14:32:21:       keepAliveMsecs: 1000,
-2025-01-15T14:32:21:       keepAlive: true,
-2025-01-15T14:32:21:       maxSockets: 5,
-2025-01-15T14:32:21:       maxFreeSockets: 2,
-2025-01-15T14:32:21:       scheduling: 'lifo',
-2025-01-15T14:32:21:       maxTotalSockets: Infinity,
-2025-01-15T14:32:21:       totalSocketCount: 1,
-2025-01-15T14:32:21:       [Symbol(shapeMode)]: false,
-2025-01-15T14:32:21:       [Symbol(kCapture)]: false
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     method: 'post',
-2025-01-15T14:32:21:     url: 'http://127.0.0.1:8080',
-2025-01-15T14:32:21:     data: '{"cmd":"chapterSpread","cbid":"20879682908817006","OPENSESSID":"ada39ae2c1286d1be3bd32e300951fff"}'
-2025-01-15T14:32:21:   },
-2025-01-15T14:32:21:   request: <ref *1> Writable {
-2025-01-15T14:32:21:     _events: {
-2025-01-15T14:32:21:       close: undefined,
-2025-01-15T14:32:21:       error: [Function: handleRequestError],
-2025-01-15T14:32:21:       prefinish: undefined,
-2025-01-15T14:32:21:       finish: undefined,
-2025-01-15T14:32:21:       drain: undefined,
-2025-01-15T14:32:21:       response: [Function: handleResponse],
-2025-01-15T14:32:21:       socket: [Array],
-2025-01-15T14:32:21:       timeout: undefined,
-2025-01-15T14:32:21:       abort: undefined
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     _writableState: WritableState {
-2025-01-15T14:32:21:       highWaterMark: 16384,
-2025-01-15T14:32:21:       length: 0,
-2025-01-15T14:32:21:       corked: 0,
-2025-01-15T14:32:21:       onwrite: [Function: bound onwrite],
-2025-01-15T14:32:21:       writelen: 0,
-2025-01-15T14:32:21:       bufferedIndex: 0,
-2025-01-15T14:32:21:       pendingcb: 0,
-2025-01-15T14:32:21:       [Symbol(kState)]: 17580812,
-2025-01-15T14:32:21:       [Symbol(kBufferedValue)]: null
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     _maxListeners: undefined,
-2025-01-15T14:32:21:     _options: {
-2025-01-15T14:32:21:       maxRedirects: 21,
-2025-01-15T14:32:21:       maxBodyLength: Infinity,
-2025-01-15T14:32:21:       protocol: 'http:',
-2025-01-15T14:32:21:       path: '/',
-2025-01-15T14:32:21:       method: 'POST',
-2025-01-15T14:32:21:       headers: [Object: null prototype],
-2025-01-15T14:32:21:       agents: [Object],
-2025-01-15T14:32:21:       auth: undefined,
-2025-01-15T14:32:21:       family: undefined,
-2025-01-15T14:32:21:       beforeRedirect: [Function: dispatchBeforeRedirect],
-2025-01-15T14:32:21:       beforeRedirects: [Object],
-2025-01-15T14:32:21:       hostname: '127.0.0.1',
-2025-01-15T14:32:21:       port: '8080',
-2025-01-15T14:32:21:       agent: [Agent],
-2025-01-15T14:32:21:       nativeProtocols: [Object],
-2025-01-15T14:32:21:       pathname: '/'
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     _ended: true,
-2025-01-15T14:32:21:     _ending: true,
-2025-01-15T14:32:21:     _redirectCount: 0,
-2025-01-15T14:32:21:     _redirects: [],
-2025-01-15T14:32:21:     _requestBodyLength: 98,
-2025-01-15T14:32:21:     _requestBodyBuffers: [ [Object] ],
-2025-01-15T14:32:21:     _eventsCount: 3,
-2025-01-15T14:32:21:     _onNativeResponse: [Function (anonymous)],
-2025-01-15T14:32:21:     _currentRequest: ClientRequest {
-2025-01-15T14:32:21:       _events: [Object: null prototype],
-2025-01-15T14:32:21:       _eventsCount: 7,
-2025-01-15T14:32:21:       _maxListeners: undefined,
-2025-01-15T14:32:21:       outputData: [],
-2025-01-15T14:32:21:       outputSize: 0,
-2025-01-15T14:32:21:       writable: true,
-2025-01-15T14:32:21:       destroyed: false,
-2025-01-15T14:32:21:       _last: false,
-2025-01-15T14:32:21:       chunkedEncoding: false,
-2025-01-15T14:32:21:       shouldKeepAlive: true,
-2025-01-15T14:32:21:       maxRequestsOnConnectionReached: false,
-2025-01-15T14:32:21:       _defaultKeepAlive: true,
-2025-01-15T14:32:21:       useChunkedEncodingByDefault: true,
-2025-01-15T14:32:21:       sendDate: false,
-2025-01-15T14:32:21:       _removedConnection: false,
-2025-01-15T14:32:21:       _removedContLen: false,
-2025-01-15T14:32:21:       _removedTE: false,
-2025-01-15T14:32:21:       strictContentLength: false,
-2025-01-15T14:32:21:       _contentLength: '98',
-2025-01-15T14:32:21:       _hasBody: true,
-2025-01-15T14:32:21:       _trailer: '',
-2025-01-15T14:32:21:       finished: true,
-2025-01-15T14:32:21:       _headerSent: true,
-2025-01-15T14:32:21:       _closed: false,
-2025-01-15T14:32:21:       socket: [Socket],
-2025-01-15T14:32:21:       _header: 'POST / HTTP/1.1\r\n' +
-2025-01-15T14:32:21:         'Accept: application/json, text/plain, */*\r\n' +
-2025-01-15T14:32:21:         'Content-Type: application/json\r\n' +
-2025-01-15T14:32:21:         'User-Agent: axios/1.7.7\r\n' +
-2025-01-15T14:32:21:         'Content-Length: 98\r\n' +
-2025-01-15T14:32:21:         'Accept-Encoding: gzip, compress, deflate, br\r\n' +
-2025-01-15T14:32:21:         'Host: 127.0.0.1:8080\r\n' +
-2025-01-15T14:32:21:         'Connection: keep-alive\r\n' +
-2025-01-15T14:32:21:         '\r\n',
-2025-01-15T14:32:21:       _keepAliveTimeout: 0,
-2025-01-15T14:32:21:       _onPendingData: [Function: nop],
-2025-01-15T14:32:21:       agent: [Agent],
-2025-01-15T14:32:21:       socketPath: undefined,
-2025-01-15T14:32:21:       method: 'POST',
-2025-01-15T14:32:21:       maxHeaderSize: undefined,
-2025-01-15T14:32:21:       insecureHTTPParser: undefined,
-2025-01-15T14:32:21:       joinDuplicateHeaders: undefined,
-2025-01-15T14:32:21:       path: '/',
-2025-01-15T14:32:21:       _ended: false,
-2025-01-15T14:32:21:       res: null,
-2025-01-15T14:32:21:       aborted: false,
-2025-01-15T14:32:21:       timeoutCb: [Function: emitRequestTimeout],
-2025-01-15T14:32:21:       upgradeOrConnect: false,
-2025-01-15T14:32:21:       parser: null,
-2025-01-15T14:32:21:       maxHeadersCount: null,
-2025-01-15T14:32:21:       reusedSocket: false,
-2025-01-15T14:32:21:       host: '127.0.0.1',
-2025-01-15T14:32:21:       protocol: 'http:',
-2025-01-15T14:32:21:       _redirectable: [Circular *1],
-2025-01-15T14:32:21:       [Symbol(shapeMode)]: false,
-2025-01-15T14:32:21:       [Symbol(kCapture)]: false,
-2025-01-15T14:32:21:       [Symbol(kBytesWritten)]: 0,
-2025-01-15T14:32:21:       [Symbol(kNeedDrain)]: false,
-2025-01-15T14:32:21:       [Symbol(corked)]: 0,
-2025-01-15T14:32:21:       [Symbol(kOutHeaders)]: [Object: null prototype],
-2025-01-15T14:32:21:       [Symbol(errored)]: null,
-2025-01-15T14:32:21:       [Symbol(kHighWaterMark)]: 16384,
-2025-01-15T14:32:21:       [Symbol(kRejectNonStandardBodyWrites)]: false,
-2025-01-15T14:32:21:       [Symbol(kUniqueHeaders)]: null
-2025-01-15T14:32:21:     },
-2025-01-15T14:32:21:     _currentUrl: 'http://127.0.0.1:8080/',
-2025-01-15T14:32:21:     _timeout: null,
-2025-01-15T14:32:21:     [Symbol(shapeMode)]: true,
-2025-01-15T14:32:21:     [Symbol(kCapture)]: false
-2025-01-15T14:32:21:   },
-2025-01-15T14:32:21:   cause: Error: socket hang up
-2025-01-15T14:32:21:       at Socket.socketOnEnd (node:_http_client:535:25)
-2025-01-15T14:32:21:       at Socket.emit (node:events:531:35)
-2025-01-15T14:32:21:       at endReadableNT (node:internal/streams/readable:1696:12)
-2025-01-15T14:32:21:       at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
-2025-01-15T14:32:21:     code: 'ECONNRESET'
-2025-01-15T14:32:21:   }
-2025-01-15T14:32:21: }
-=======
-2025-01-14T22:58:38: 
-2025-01-14T22:58:38: > heiyan@1.0.0 start
-2025-01-14T22:58:38: > node tg_factory_main.js
-2025-01-14T22:58:38: 
->>>>>>> c12cf6fe2f8680704228d1e0ad03fffd8edcd735

+ 0 - 22
logs/out.log

@@ -1,22 +0,0 @@
-<<<<<<< HEAD
-2025-01-15T14:14:13: 
-2025-01-15T14:14:13: > heiyan@1.0.0 start
-2025-01-15T14:14:13: > node tg_factory_main.js
-2025-01-15T14:14:13: 
-2025-01-15T14:14:16: Connected to Redis
-2025-01-15T14:30:06: 
-2025-01-15T14:30:06: > heiyan@1.0.0 start
-2025-01-15T14:30:06: > node tg_factory_main.js
-2025-01-15T14:30:06: 
-2025-01-15T14:30:09: Connected to Redis
-2025-01-15T14:32:20: 
-2025-01-15T14:32:20: > heiyan@1.0.0 start
-2025-01-15T14:32:20: > node tg_factory_main.js
-2025-01-15T14:32:20: 
-2025-01-15T14:32:21: Connected to Redis
-=======
-2025-01-14T22:58:38: 
-2025-01-14T22:58:38: > heiyan@1.0.0 start
-2025-01-14T22:58:38: > node tg_factory_main.js
-2025-01-14T22:58:38: 
->>>>>>> c12cf6fe2f8680704228d1e0ad03fffd8edcd735

BIN
src/api/hy/qr.gif


BIN
src/api/hy/qr_resized.gif


+ 3 - 1
src/api/yw/getActiveInfo.js

@@ -3,11 +3,13 @@ const fetch = require('node-fetch'); // Node.js 18以下版本需要安装 node-
 const tools = require('../../../tools');
 const config  = require('../../../etc/config.json');
 const redis_help = require('../../use_redis');
+const helper = require('../../helper');
 const CMD = {}
 
 CMD.getActiveInfo = async function() {
   try{
       let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
+      let time = helper.getCurrentUnixTimestamp()
       let response = await fetch("https://open.yuewen.com/api/Account/getActiveInfo", {
         "headers": {
           "accept": "application/json, text/plain, */*",
@@ -19,7 +21,7 @@ CMD.getActiveInfo = async function() {
           "sec-fetch-dest": "empty",
           "sec-fetch-mode": "cors",
           "sec-fetch-site": "same-origin",
-          "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=vN8OkvTZZfzerTHhodh7rc81; OPENSESSID=${OPENSESSID}; yw_open_token=6785d8c2ec046; sidebarStatus=0; is_read_notice=6785d8c2ec046`,
+          "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=${time}; csrfToken=vN8OkvTZZfzerTHhodh7rc81; OPENSESSID=${OPENSESSID}; yw_open_token=6785d8c2ec046; sidebarStatus=0; is_read_notice=6785d8c2ec046`,
           "Referer": "https://open.yuewen.com/new/dashboard",
           "Referrer-Policy": "strict-origin-when-cross-origin"
         },

+ 40 - 59
src/api/yw/get_book_tg_chapter_id.js

@@ -3,74 +3,55 @@ const tools = require('../../../tools');
 const config  = require('../../../etc/config.json');
 const redis_help = require('../../use_redis');
 const HttpClient = require('../../HttpClient');
+const helper = require('../../helper');
 const CMD = {}
 
 CMD.get_book_tg_chapter_id = async function(book_id) {
     try{
         let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
-        // let url = `https://open.yuewen.com/api/wechatspread/bookSpread?cbid=30554680307186706&page=1&version=2&order_field=allwords&order_type=0&content_type=0&category2=-1&isfinish=-1`
-      
-        // let headers =  {
-        //     'Accept': 'application/json, text/plain, */*',
-        //     'Cookie': `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=vN8OkvTZZfzerTHhodh7rc81; OPENSESSID=${OPENSESSID}; yw_open_token=6785d8c2ec046; is_read_notice=6785d8c2ec046; sidebarStatus=0`,
-        //     'User-Agent': 'axios/1.7.7'
-        // }
-        let client = tools.getOneNewClinet()
-
-        let postData = {
-            cmd:"chapterSpread",
-            cbid:book_id,
-            OPENSESSID:OPENSESSID
+        // let client = tools.getOneNewClinet()
+        // let postData = {
+        //     cmd:"chapterSpread",
+        //     cbid:book_id,
+        //     OPENSESSID:OPENSESSID
             
-        }
-        const response = await client.post(config.python_config.host, postData)
-        
-        console.log("response.data.received_data:",response)
-
-        // let client = new HttpClient()
-        // const response = await client.proxyGet({
-        //     url:url,
-        //     headers:{
-        //         "cookie": "Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=vN8OkvTZZfzerTHhodh7rc81; OPENSESSID=b46a306fdc15d6b4ee60c41095b1cdd5; yw_open_token=6785d8c2ec046; is_read_notice=6785d8c2ec046; sidebarStatus=0"
-        //     }
-        // })
+        // }
+        // let response = await client.post(config.python_config.host, postData)
+        // console.log("response.data.received_data:",response.data.received_data)
+        // response = response.data.received_data
      
-        console.log("get_book_tg_chapter_id:",response)
-        // await require('./getActiveInfo').getActiveInfo()
-        // let url = `https://open.yuewen.com/api/wechatspread/bookSpread?cbid=20879682908817006&page=1&version=2&order_field=allwords&order_type=0&content_type=0&category2=-1&isfinish=-1`
-        // let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
-        // console.log("url:",url,OPENSESSID)
-        // const response =   await fetch(url, {
-        //     "headers": {
-        //       "accept": "application/json, text/plain, */*",
-        //       "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
-        //       "priority": "u=1, i",
-        //       "sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
-        //       "sec-ch-ua-mobile": "?0",
-        //       "sec-ch-ua-platform": "\"Windows\"",
-        //       "sec-fetch-dest": "empty",
-        //       "sec-fetch-mode": "cors",
-        //       "sec-fetch-site": "same-origin",
-        //       "Content-Type" : "application/json; charset=utf-8",
-        //       "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=vN8OkvTZZfzerTHhodh7rc81; OPENSESSID=${OPENSESSID}; yw_open_token=6785d8c2ec046; is_read_notice=6785d8c2ec046; sidebarStatus=0`,
-        //       "Referer": "https://open.yuewen.com/new/library",
-        //       "Referrer-Policy": "strict-origin-when-cross-origin"
-        //     },
-        //     "body": null,
-        //     "method": "GET"
-        //   });
-    
-        //   const data = await response.json();
-        //   console.log('响应数据:', response);
-        //   if(data.code!=0){
-        //       throw data
-        //   }
+        await require('./getActiveInfo').getActiveInfo()
+        let timestamp = helper.getCurrentUnixTimestamp()
+        let url = `https://open.yuewen.com/api/wechatspread/chapterSpread?cbid=${book_id}&page=1&version=2&order_field=allwords&order_type=0&content_type=0&category2=-1&isfinish=-1`
+        const response =   await fetch(url, {
+            "headers": {
+              "accept": "application/json, text/plain, */*",
+              "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
+              "priority": "u=1, i",
+              "sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
+              "sec-ch-ua-mobile": "?0",
+              "sec-ch-ua-platform": "\"Windows\"",
+              "sec-fetch-dest": "empty",
+              "sec-fetch-mode": "cors",
+              "sec-fetch-site": "same-origin",
+              "Content-Type" : "application/json; charset=utf-8",
+              "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=${timestamp}; csrfToken=vN8OkvTZZfzerTHhodh7rc81; OPENSESSID=${OPENSESSID}; yw_open_token=6785d8c2ec046; is_read_notice=6785d8c2ec046; sidebarStatus=0`,
+              "Referer": "https://open.yuewen.com/new/library",
+              "Referrer-Policy": "strict-origin-when-cross-origin"
+            },
+            "body": null,
+            "method": "GET"
+          });
     
-        //   console.log('响应状态:', response.status);
-        //   console.log('响应数据:', data);
-        //   return data.data.chapterList[0];
+          const data =  await response.json();
+          if(data.code!=0){
+              throw data
+          }
+          console.log('get_book_tg_chapter_id::响应状态:', response.status);
+          console.log('get_book_tg_chapter_id::响应数据:', data);
+          return data.data.chapterList[0];
     }catch(error){
-        console.error('请求错误:', error);
+        console.error('get_book_tg_chapter_id::请求错误:', error);
         return null;
     }
 

+ 3 - 1
src/api/yw/get_yw_recharge_template.js

@@ -3,12 +3,14 @@ const fetch = require('node-fetch'); // Node.js 18以下版本需要安装 node-
 const tools = require('../../../tools');
 const config  = require('../../../etc/config.json');
 const redis_help = require('../../use_redis');
+const helper = require('../../helper');
 const CMD = {}
 
 CMD.get_recharge_template = async function (yw_id) {
     await require('./switchApp').switchApp(yw_id)
     try {
         let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
+        let timestamp = helper.getCurrentUnixTimestamp()
         console.log("OPENSESSID:",OPENSESSID)
         const response =  await fetch("https://open.yuewen.com/api/WechatWebsite/PageListChargeSettingTemplates", {
             "headers": {
@@ -21,7 +23,7 @@ CMD.get_recharge_template = async function (yw_id) {
               "sec-fetch-dest": "empty",
               "sec-fetch-mode": "cors",
               "sec-fetch-site": "same-origin",
-              "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=1`,
+              "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=${timestamp}; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=1`,
               "Referer": "https://open.yuewen.com/new/library",
               "Referrer-Policy": "strict-origin-when-cross-origin"
             },

+ 3 - 1
src/api/yw/switchApp.js

@@ -2,12 +2,14 @@
 const fetch = require('node-fetch'); // Node.js 18以下版本需要安装 node-fetch
 const config  = require('../../../etc/config.json');
 const redis_help = require('../../use_redis');
+const helper = require('../../helper');
 const CMD = {}
 
 CMD.switchApp = async function(yw_id) {
     // let res =  await require('./yw_login').yw_login()
     // console.log("res:",res.headers)
     let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
+    let time = helper.getCurrentUnixTimestamp()
     return await fetch("https://open.yuewen.com/api/account/switchApp", {
         "headers": {
           "accept": "application/json, text/plain, */*",
@@ -20,7 +22,7 @@ CMD.switchApp = async function(yw_id) {
           "sec-fetch-dest": "empty",
           "sec-fetch-mode": "cors",
           "sec-fetch-site": "same-origin",
-          "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=0`,
+          "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=${time}; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=0`,
           "Referer": "https://open.yuewen.com/new/library",
           "Referrer-Policy": "strict-origin-when-cross-origin"
         },

+ 2 - 1
src/api/yw/yw_search_book.js

@@ -6,6 +6,7 @@ const CMD = {}
 CMD.search_id = async function (bookId) {
     try {
         let OPENSESSID = await redis_help.getKeyValue("OPENSESSID")
+        let time = helper.getCurrentUnixTimestamp()
         const response = await fetch(`https://open.yuewen.com/api/wechatspread/bookSpread?cbid=${bookId}&page=1&version=2&order_field=allwords&order_type=0&content_type=1&category1=-1&allwords=-1&category2=-1&isfinish=-1&level=-1`, {
             "headers": {
               "accept": "application/json, text/plain, */*",
@@ -17,7 +18,7 @@ CMD.search_id = async function (bookId) {
               "sec-fetch-dest": "empty",
               "sec-fetch-mode": "cors",
               "sec-fetch-site": "same-origin",
-              "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=1736394515; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=0`,
+              "cookie": `Hm_lvt_990f9ab9737a266517417cc2949bb3f4=${time}; csrfToken=9EeGTClKZ3EJFZjIQDcVozZj; OPENSESSID=${OPENSESSID}; yw_open_token=6784835e6c51a; is_read_notice=6784835e6c51a; sidebarStatus=0`,
               "Referer": "https://open.yuewen.com/new/library",
               "Referrer-Policy": "strict-origin-when-cross-origin"
             },

+ 40 - 0
test.js

@@ -0,0 +1,40 @@
+const crypto = require('crypto');
+
+const APPFLAG = 'dpfx91801';
+const APPSECRET = '88fa244d77fce2b9b92c83a0dc88e38d';
+
+function sign(params) {
+    // 1. 对参数key做ASCII升序排序
+    const sortedKeys = Object.keys(params).sort();
+
+    let str = '';
+    for (let key of sortedKeys) {
+        if (key === 'sign') {
+            // 签名串中不包含sign字段
+            continue;
+        }
+        // 2. 拼接key和value,不添加任何字符
+        str += key + params[key];
+    }
+
+    // 3. 在头部拼接appsecret
+    str = APPSECRET + str;
+
+    // 4. 计算md5值并转换为大写
+    const hash = crypto.createHash('md5').update(str, 'utf8').digest('hex');
+    return hash.toUpperCase();
+}
+
+let params = {
+    'appflag': APPFLAG,           // 通用参数appflag必传
+    'timestamp': String(Math.floor(Date.now() / 1000))  // 通用参数timestamp实时获取
+};
+
+console.log("params:",params)
+
+// let helper = require('./src/helper')
+// let timestamp = helper.getCurrentUnixTimestamp()
+
+// 通用参数sign计算生成
+params['sign'] = sign(params);
+console.log(params);

+ 14 - 0
test.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# 设置显示服务
+export DISPLAY=:99
+
+# 启动虚拟显示服务
+Xvfb :99 -screen 0 1920x1080x24 > /dev/null 2>&1 &
+sleep 1
+
+# 运行Python脚本
+python3.8 geetest_crack.py
+
+# 清理Xvfb进程
+pkill Xvfb

+ 5 - 4
tg_factory_main.js

@@ -38,11 +38,12 @@ if(config.isDebug){
             if(isInit){
                 return
             }
-            isInit = true
+            // isInit = true
+            // await redis_help.setKeyValue("OPENSESSID","e1eb930167e205912909fcfaa6e5c5c8")
             // await require('./src/api/yw/get_book_tg_chapter_id').get_book_tg_chapter_id("20879682908817006")
             // await redis_help.setKeyValue("OPENSESSID","ada39ae2c1286d1be3bd32e300951fff")
 
-            // // await require('./src/api/yw/getActiveInfo').getActiveInfo()
+            // await require('./src/api/yw/getActiveInfo').getActiveInfo()
 
             // let MainConfig = await redis_help.getKeyValue("MainConfig")
             // MainConfig = JSON.parse(MainConfig)
@@ -54,8 +55,8 @@ if(config.isDebug){
             // let main_info = getMainInfoById(MainConfig,178) //180
 
             // let data = {
-            //     product_id:"20879682908817006",
-            //     product_name:"和美女同事流落荒岛的日子"
+            //     product_id:"27524924504527406",
+            //     product_name:"为爱冲锋的勇士"
             // }
             // // console.log("PlatformInfo:",PlatformInfo)
             // // console.log("main_info:",main_info)