# -*- coding: utf-8 -*- from playwright.async_api import Page import asyncio from auto_media_publisher.uploaders.uploader_base import UploaderBase CONTENT_UPLOAD_URL="https://member.bilibili.com/platform/upload/video/frame" VIDEO_PUBLISH_SECCESSFULL_URL = "https://cp.kuaishou.com/article/manage/video?status=2&from=publish" class UploaderBilibili(UploaderBase): async def set_schedule_time(self, page): try: await page.locator(".switch-roll").first.click() await asyncio.sleep(1) scheduled_date = self.scheduled_time.strftime("%Y-%m-%d") scheduled_month = self.scheduled_time.strftime("%Y年%m月") exact_day = str(self.scheduled_time.day) await page.locator(".date-show-icon").first.click() await asyncio.sleep(1) if scheduled_month != await page.locator("p.date-picker-nav-title").text_content(): await page.locator(".next-btn-day.icon-sprite.icon-sprite-ic_into").click() await asyncio.sleep(1) await page.get_by_text(exact_day, exact=True).click() await asyncio.sleep(1) exact_hour = f"{self.scheduled_time.hour:02d}" exact_min = f"{self.scheduled_time.minute:02d}" await page.locator(".date-picker-timer > .date-show-icon").click() await asyncio.sleep(0.5) await page.locator('div.time-picker-panel-select-wrp').nth(0).locator(f'span:nth-child({self.scheduled_time.hour + 1})').click() minute_index = ((self.scheduled_time.minute // 5) * 5 // 5) + 1 # 序号从1开始 await page.locator('div.time-picker-panel-select-wrp').nth(1).locator(f'span:nth-child({minute_index})').click() await asyncio.sleep(1) except Exception as e: self.logger.error(f'[ERROR ] {self.user} , {self.platform} ,设置 发布时间 发生错误:{e}') async def set_cover_image(self,page): try: # 通过点击 div.content 触发文件选择框的打开 upload_div = page.locator("div.cover-main-upload div.content") async with page.expect_file_chooser() as fc_info: await upload_div.click() file_chooser = await fc_info.value await file_chooser.set_files(self.path_cover) # 确保上传完成 await page.locator('button:has-text("完成")').click(timeout=30000) # 点击“完成”按钮,确保上传完成 except Exception as e: self.logger.error(f'[ERROR ] {self.user} , {self.platform} ,设置 封面 发生错误:{e}') async def upload_media_and_wait(self,page): try: upload_div = page.get_by_text("拖拽到此处也可上传上传视频") await upload_div.wait_for(state="visible", timeout=10000) async with page.expect_file_chooser() as fc_info: await upload_div.click() file_chooser = await fc_info.value await file_chooser.set_files(self.path_media) await asyncio.sleep(2) max_retries = 60 # 设置最大重试次数,最大等待时间为 2 分钟 retry_count = 0 while retry_count < max_retries: try: number = await page.locator('span.success', has_text="上传完成").count() if number > 0: self.logger.info("视频上传完毕") break else: if retry_count % 5 == 0: self.logger.info("正在上传视频中...") await asyncio.sleep(2) except Exception as e: self.logger.error(f"检查上传状态时发生错误: {e}") await asyncio.sleep(2) # 等待 2 秒后重试 retry_count += 1 if retry_count == max_retries: self.logger.warning("超过最大重试次数,视频上传可能未完成。") except Exception as e: self.logger.error(f'[ERROR ] {self.user} , {self.platform} ,设置 封面 发生错误:{e}') async def set_title_and_description(self,page): try: self.logger.info("正在填充标题和话题...") await page.get_by_placeholder("请输入稿件标题").click() await page.get_by_placeholder("请输入稿件标题").press("ControlOrMeta+a") await page.get_by_placeholder("请输入稿件标题").fill(self.title) await page.locator('div[data-placeholder="填写更全面的相关信息,让更多的人能找到你的视频吧"]').click() description_tags = self.description + ' ' + ' '.join(f"#{tag}" for tag in self.tags) await page.locator('div[data-placeholder="填写更全面的相关信息,让更多的人能找到你的视频吧"]').fill(description_tags) # 快手只能添加3个话题 for index, tag in enumerate(self.tags[:7], start=1): self.logger.info("正在添加第%s个话题" % index) await page.get_by_placeholder("按回车键Enter创建标签").nth(0).click() await page.keyboard.type(tag) await page.keyboard.press("Enter") await asyncio.sleep(1) except Exception as e: self.logger.error(f'[ERROR ] {self.user} , {self.platform} ,设置 标题和描述 发生错误:{e}') async def _upload_core(self) -> bool: try: # 创建一个新的页面 page = await self.context.new_page() # 访问指定的 URL await page.goto(CONTENT_UPLOAD_URL, timeout=120000) self.logger.info('正在上传-------{}.mp4'.format(self.title)) await page.wait_for_url(CONTENT_UPLOAD_URL, timeout=120000) await self.upload_media_and_wait(page) await self.set_title_and_description(page) await self.set_cover_image(page) # select CLass if self.category: try: await page.locator(".select-controller").first.click() await asyncio.sleep(1) await page.get_by_title(self.category).click() except Exception as e: self.logger.error(f'[ bilibili ] setting catalog error. {e}') # 定时发布 if self.scheduled_time != 0: await self.set_schedule_time(page) # 判断视频是否发布成功 while True: try: publish_button = page.get_by_text("立即投稿", exact=True) if await publish_button.count() > 0: await publish_button.click() await asyncio.sleep(1) await page.get_by_role("button", name="再投一个").wait_for(timeout=10000) self.logger.info("视频发布成功") break except Exception as e: self.logger.info(f"视频正在发布中... 错误: {e}") await page.screenshot(full_page=True) await asyncio.sleep(1) await self.context.storage_state(path=self.cookie_path) # 保存cookie self.logger.info('cookie更新完毕!') await asyncio.sleep(3) # 这里延迟是为了方便眼睛直观的观看 return True except Exception as e: self.logger.error(f"{self.user} upload video {self.path_media} fails, error is :{e}") return False