wangzhibo
2025-07-30 25087cbe79c8c4992551477d55d9db8bbea2202e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# -*- coding: utf-8 -*-
from datetime import datetime
 
from playwright.async_api import Page
import pyperclip
import asyncio
from auto_media_publisher.uploaders.uploader_base import UploaderBase
 
CONTENT_UPLOAD_URL="https://x.com/home"
 
VIDEO_PUBLISH_SECCESSFULL_URL = "https://www.tiktok.com/tiktokstudio/content"
                                 
 
class UploaderTwitterX(UploaderBase):
    
    def get_year_index(self,publish_year:int)-> int:
        current_year = datetime.now().year  # 获取当前年份
        base_year = current_year  # 设定基准年份,例如当前年份
        base_index = 3  # 当前年份对应序号为4
        # 计算目标年份相对于当前年份的序号
        return base_index - (publish_year - base_year)
 
 
    async def setPostScheduleDateTime(self, page):
        self.logger.info(f"start to set publish date time ...{datetime}")
        await self.set_single_option(page,'#SELECTOR_3',self.scheduled_time.year) # year
        await self.set_single_option(page,'#SELECTOR_1', self.scheduled_time.month) # month
        await self.set_single_option(page,'#SELECTOR_2', self.scheduled_time.day) # day
        await self.set_single_option(page,'#SELECTOR_4', self.scheduled_time.hour) # hour
        await self.set_single_option(page,'#SELECTOR_5', self.scheduled_time.minute) # min
        # 确认按钮
        await page.click('span:text("确认")')
        await asyncio.sleep(1)
 
    async def set_single_option(self,page,selector,value):
        # Ensure the select element is visible and available
        select_locator = page.locator(selector)
        # Select the option by its value
        await select_locator.select_option(value=str(value))  # Select by value
           
 
    async def _upload_core(self) -> bool:
        try:
            page = await self.context.new_page()
            await page.goto(CONTENT_UPLOAD_URL, timeout=120000)
            self.logger.info(f'[+]Uploading-------{self.title}.mp4')
 
            # 等待页面加载完成
            await page.wait_for_url("**/home")
 
            if "/home" not in page.url:
                self.logger.info("账号未登录")
                self.logger.info(f"账号未登录:{self.cookie_path}")
                return False
 
            self.logger.info(f"twitterX {self.user} 账号已登录")
 
            # 发布视频流程
            try:
                upload_button = await page.wait_for_selector('button[aria-label="添加照片或视频"], button[aria-label="添加媒体"]', timeout=10000)
                await upload_button.click()
 
                # 等待文件选择器出现并上传视频
                file_input = await page.wait_for_selector('input[type="file"]', timeout=10000)
                await file_input.set_input_files(self.path_media)
            except Exception as e:
                self.logger.info("发布视频失败,可能网页加载失败了\n", e)
                self.logger.info("发布视频失败,可能网页加载失败了")
 
            self.logger.info("视频标题输入完毕,等待发布")
            await page.wait_for_timeout(5000)  # 等待 5 秒
 
            # 设置发布的时间
            datetime_button = await page.wait_for_selector('button[aria-label="预排期帖子"]', timeout=10000)
            await datetime_button.click()
 
            await page.wait_for_timeout(2000)  # 等待 2 秒
 
            await self.setPostScheduleDateTime(page)
 
            video_desc = self.title+"\n" + ' '.join(['#' + tag  for tag in self.tags])
            pyperclip.copy(video_desc)
 
            # 输入视频描述
            description_field = await page.wait_for_selector('[aria-label="帖子文本"] div div div', timeout=10000)
            await description_field.click()
 
            # 模拟 Ctrl + V 粘贴
            await page.keyboard.down("Control")
            await page.keyboard.press("V")
            await page.keyboard.up("Control")
            await page.mouse.click(0, 0)
 
 
            # 点击发布按钮
            publish_button_locator = page.locator('button:has-text("发帖"), button:has-text("安排表")')
 
            # 等待按钮可见并点击
            await publish_button_locator.wait_for(state='visible', timeout=10000)  # 等待最多 10 秒
            await publish_button_locator.click()
 
            while True:
                try:
                    button = page.locator('button:has-text("发帖")')
                    # 最多等待 10 秒,每 0.5 秒检查一次
                    for _ in range(20):
                        is_disabled = await button.get_attribute("disabled")
                        if is_disabled is not None:
                            self.logger.info("按钮已禁用,发帖成功")
                            break
                        await asyncio.sleep(0.5)
                    else:
                        self.logger.info("等待超时:按钮未变为禁用")
                    self.logger.info("  [-] video published success")
                    break
                except Exception as e:
                    self.logger.exception(f"  [-] Exception: {e}")
                    self.logger.info("  [-] video publishing")
                    await asyncio.sleep(0.5)
 
            self.logger.info("视频发布成功")
           
            await self.context.storage_state(path=f"{self.cookie_path}")  # save cookie
            self.logger.info('twitterX  [-] update cookie!')
            await asyncio.sleep(2)  # close delay for look the video status
          
            
            return True
 
        except Exception as e:
            self.logger.info(f"异常类型: {type(e).__name__}")  # 打印异常的类型
            self.logger.info(f"异常消息: {str(e)}")          # 打印异常消息
            self.logger.info(f"异常详细信息: {repr(e)}")     # 打印异常的完整表示
            self.logger.info(f"异常的所有属性:", {e.__dict__})
            self.logger.info("视频发布失败,请管理员处理。")
 
            return False