import asyncio import contextlib import os import re import time from asyncio import sleep from io import BytesIO from typing import List, Dict from pyrogram.errors import FloodWait from pyrogram.types import Message from defs.glover import lofter_channel from defs.lofter import lofter_link from models.services.lofter import LofterPost as LofterPostModel from models.models.lofter import Lofter as LofterModel from init import request, bot pattern = re.compile(r"<[^>]+>", re.S) class LofterPost: def __init__(self, url: str, offset: str): try: self.grainId = int(url) except ValueError: self.grainId = int(url[url.find("grainId=") + 8 :].split("&")[0]) try: self.offset = int(offset) except ValueError: self.offset = 0 self.url = f"https://api.lofter.com/api-grain/grain/getH5Detail.json?grainId={self.grainId}&offset=" async def get_data(self): if self.offset == -1: return None res = await request.get(self.url + str(self.offset)) assert res.status_code == 200 return res.json() class Item: def __init__( self, url, origin_url, title, user_id, username, name, tags, comment, post_id, first, static, ): self.url = url.split("?")[0] self.origin_url = origin_url self.user_id = str(user_id) self.username = username self.post_id = post_id self.first = first self.static = static title = pattern.sub("\n", title).strip()[:500] self.text = ( f"Lofter Status Info\n\n" f"{title}\n\n" f'✍️ {name}\n' f"{tags}\n" f"{comment}" ) async def check_exists(self): return await LofterPostModel.get_by_post_and_user_id( self.user_id, self.post_id ) async def add_to_db(self): post = LofterModel( user_id=self.user_id, username=self.username, post_id=self.post_id, timestamp=int(time.time()), ) await LofterPostModel.add_post(post) async def init(self): file = await request.get(self.url, timeout=30) file = BytesIO(file.content) file.name = os.path.basename(self.url) return file async def upload(self, file): try: if self.static: await bot.send_document( lofter_channel, file, caption=self.text, disable_notification=True, reply_markup=lofter_link( self.url, self.origin_url, self.username ), ) else: await bot.send_photo( lofter_channel, file, caption=self.text, disable_notification=True, reply_markup=lofter_link( self.url, self.origin_url, self.username ), ) except FloodWait as e: await asyncio.sleep(e.value + 0.5) await self.upload(file) @staticmethod def parse_data(data: List[Dict]) -> List[Item]: datas = [] for i in data: if post_data := i.get("postData"): user_id, username, name, comment = 0, "", "", "" if blog_info := post_data.get("blogInfo"): user_id = blog_info.get("blogId", 0) username = blog_info.get("blogName", "") name = blog_info.get("blogNickName", "") if post_count_view := post_data.get("postCountView"): a = post_count_view.get("responseCount", 0) b = post_count_view.get("hotCount", 0) c = post_count_view.get("favoriteCount", 0) comment = f"评论({a}) 热度({b}) 喜欢({c})" if post_view := post_data.get("postView"): title = post_view.get("digest", "") permalink = post_view.get("permalink", "") origin_url = f"https://{username}.lofter.com/post/{permalink}" tags = "".join(f"#{i} " for i in post_view.get("tagList", [])) if photo_post_view := post_view.get("photoPostView"): if photo_links := photo_post_view.get("photoLinks"): first = True for photo in photo_links: if url := photo.get("orign"): width = photo.get("ow", 0) height = photo.get("oh", 0) static = abs(height - width) > 1300 datas.append( LofterPost.Item( url, origin_url, title, user_id, username, name, tags, comment, permalink, first, static, ) ) first = False return datas async def get_items(self) -> List[Item]: datas: List[LofterPost.Item] = [] data = await self.get_data() if data: data = data.get("data", {}) if data: self.offset = data.get("offset", 0) if posts := data.get("posts", []): datas = self.parse_data(posts) return datas async def upload(self, message: Message): msg = await message.reply_text("正在上传中...") success, error, skip = 0, 0, 0 temp_skip = False while True: try: items = await self.get_items() if not items: break for item in items: try: if item.first: if await item.check_exists(): temp_skip = True skip += 1 await sleep(0.5) continue else: temp_skip = False elif temp_skip: skip += 1 continue file = await item.init() await item.upload(file) if item.first: await item.add_to_db() success += 1 await sleep(0.5) except Exception as e: print(f"Error uploading file: {e}") error += 1 if (success + error) % 10 == 0: with contextlib.suppress(Exception): await msg.edit( f"已成功上传{success}条,失败{error}条,跳过 {skip} 条,第 {success + error + skip} 条" ) if self.offset == -1: break except Exception as e: print(f"Error uploading file: {e}") continue await msg.edit( f"上传完成,成功{success}条,失败{error}条,跳过 {skip} 条,总共 {success + error + skip} 条" )