Skip to content

Commit

Permalink
feat: 允许自定义发表稿件时附带的文字 (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
RockChinQ committed Jul 26, 2024
1 parent b7220a9 commit 0a92c5d
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,5 @@ cython_debug/
#.idea/
venv
cache.json
metadata.json
/tests
5 changes: 5 additions & 0 deletions campux/common/entity.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import typing

import pydantic


Expand Down Expand Up @@ -44,3 +46,6 @@ class Post(pydantic.BaseModel):

time_stamp: int
"""时间戳"""

extra_text: typing.Optional[str] = None
"""额外文本"""
Empty file added campux/config/__init__.py
Empty file.
Empty file added campux/config/impls/__init__.py
Empty file.
59 changes: 59 additions & 0 deletions campux/config/impls/json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import os
import shutil
import json

from .. import model as file_model


class JSONConfigFile(file_model.ConfigFile):
"""JSON配置文件"""

def __init__(
self, config_file_name: str, template_file_name: str = None, template_data: dict = None
) -> None:
self.config_file_name = config_file_name
self.template_file_name = template_file_name
self.template_data = template_data

def exists(self) -> bool:
return os.path.exists(self.config_file_name)

async def create(self):
if self.template_file_name is not None:
shutil.copyfile(self.template_file_name, self.config_file_name)
elif self.template_data is not None:
with open(self.config_file_name, "w", encoding="utf-8") as f:
json.dump(self.template_data, f, indent=4, ensure_ascii=False)
else:
raise ValueError("template_file_name or template_data must be provided")

async def load(self, completion: bool=True) -> dict:

if not self.exists():
await self.create()

if self.template_file_name is not None:
with open(self.template_file_name, "r", encoding="utf-8") as f:
self.template_data = json.load(f)

with open(self.config_file_name, "r", encoding="utf-8") as f:
try:
cfg = json.load(f)
except json.JSONDecodeError as e:
raise Exception(f"配置文件 {self.config_file_name} 语法错误: {e}")

if completion:

for key in self.template_data:
if key not in cfg:
cfg[key] = self.template_data[key]

return cfg

async def save(self, cfg: dict):
with open(self.config_file_name, "w", encoding="utf-8") as f:
json.dump(cfg, f, indent=4, ensure_ascii=False)

def save_sync(self, cfg: dict):
with open(self.config_file_name, "w", encoding="utf-8") as f:
json.dump(cfg, f, indent=4, ensure_ascii=False)
66 changes: 66 additions & 0 deletions campux/config/impls/pymodule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import os
import shutil
import importlib
import logging

from .. import model as file_model


class PythonModuleConfigFile(file_model.ConfigFile):
"""Python模块配置文件"""

config_file_name: str = None
"""配置文件名"""

template_file_name: str = None
"""模板文件名"""

def __init__(self, config_file_name: str, template_file_name: str) -> None:
self.config_file_name = config_file_name
self.template_file_name = template_file_name

def exists(self) -> bool:
return os.path.exists(self.config_file_name)

async def create(self):
shutil.copyfile(self.template_file_name, self.config_file_name)

async def load(self, completion: bool=True) -> dict:
module_name = os.path.splitext(os.path.basename(self.config_file_name))[0]
module = importlib.import_module(module_name)

cfg = {}

allowed_types = (int, float, str, bool, list, dict)

for key in dir(module):
if key.startswith('__'):
continue

if not isinstance(getattr(module, key), allowed_types):
continue

cfg[key] = getattr(module, key)

# 从模板模块文件中进行补全
if completion:
module_name = os.path.splitext(os.path.basename(self.template_file_name))[0]
module = importlib.import_module(module_name)

for key in dir(module):
if key.startswith('__'):
continue

if not isinstance(getattr(module, key), allowed_types):
continue

if key not in cfg:
cfg[key] = getattr(module, key)

return cfg

async def save(self, data: dict):
logging.warning('Python模块配置文件不支持保存')

def save_sync(self, data: dict):
logging.warning('Python模块配置文件不支持保存')
57 changes: 57 additions & 0 deletions campux/config/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from __future__ import annotations

from . import model as file_model
from .impls import pymodule, json as json_file


managers: ConfigManager = []


class ConfigManager:
"""配置文件管理器"""

file: file_model.ConfigFile = None
"""配置文件实例"""

data: dict = None
"""配置数据"""

def __init__(self, cfg_file: file_model.ConfigFile) -> None:
self.file = cfg_file
self.data = {}

async def load_config(self, completion: bool=True):
self.data = await self.file.load(completion=completion)

async def dump_config(self):
await self.file.save(self.data)

def dump_config_sync(self):
self.file.save_sync(self.data)


async def load_python_module_config(config_name: str, template_name: str, completion: bool=True) -> ConfigManager:
"""加载Python模块配置文件"""
cfg_inst = pymodule.PythonModuleConfigFile(
config_name,
template_name
)

cfg_mgr = ConfigManager(cfg_inst)
await cfg_mgr.load_config(completion=completion)

return cfg_mgr


async def load_json_config(config_name: str, template_name: str=None, template_data: dict=None, completion: bool=True) -> ConfigManager:
"""加载JSON配置文件"""
cfg_inst = json_file.JSONConfigFile(
config_name,
template_name,
template_data
)

cfg_mgr = ConfigManager(cfg_inst)
await cfg_mgr.load_config(completion=completion)

return cfg_mgr
34 changes: 34 additions & 0 deletions campux/config/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import abc


class ConfigFile(metaclass=abc.ABCMeta):
"""配置文件抽象类"""

config_file_name: str = None
"""配置文件名"""

template_file_name: str = None
"""模板文件名"""

template_data: dict = None
"""模板数据"""

@abc.abstractmethod
def exists(self) -> bool:
pass

@abc.abstractmethod
async def create(self):
pass

@abc.abstractmethod
async def load(self, completion: bool=True) -> dict:
pass

@abc.abstractmethod
async def save(self, data: dict):
pass

@abc.abstractmethod
def save_sync(self, data: dict):
pass
12 changes: 12 additions & 0 deletions campux/core/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
from ..social import mgr as social_mgr
from ..imbot import mgr as imbot_mgr
from ..common import cache as cache_mgr
from ..config import manager as config_mgr


class Application:

cache: cache_mgr.CacheManager

meta: config_mgr.ConfigManager

@property
def cpx_api(self) -> api.CampuxAPI:
Expand Down Expand Up @@ -50,12 +53,21 @@ async def create_app() -> Application:
# 在这里加载插件
nonebot.load_plugin("campux.imbot.nbmod") # 本地插件

# 元数据
meta = await config_mgr.load_json_config("data/metadata.json", template_data={
"post_publish_text": "'#' + str(post_id)",
})

await meta.load_config()
await meta.dump_config()

# 缓存管理器
cache = cache_mgr.CacheManager()
cache.load()

ap = Application()
ap.cache = cache
ap.meta = meta

ap.bot_event_loop = asyncio.get_event_loop()

Expand Down
8 changes: 7 additions & 1 deletion campux/social/mgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ..core import app
from .qzone import api as qzone_api
from .render import apirender
from . import preproc


class SocialPlatformManager:
Expand All @@ -22,13 +23,16 @@ class SocialPlatformManager:

invalid_count: int = 0

preprocessor: preproc.PostPreprocessor

publishing_semaphore: asyncio.Semaphore = asyncio.Semaphore(1)
"""发布信号量,防止同时发布多个稿件"""

def __init__(self, ap: app.Application):
self.ap = ap
self.platform_api = qzone_api.QzoneAPI(ap)
self.renderer = apirender.IdoknowAPIRender(ap)
self.preprocessor = preproc.PostPreprocessor(ap)

async def initialize(self):
async def schedule_loop():
Expand Down Expand Up @@ -104,6 +108,8 @@ async def _publish_post(self, post_id: int):

post = await self.ap.cpx_api.get_post_info(post_id)

post = await self.preprocessor.preprocess_post(post)

images_to_post = []

images_to_post.append(
Expand All @@ -115,7 +121,7 @@ async def _publish_post(self, post_id: int):
images_to_post.append(image)

tid = await self.platform_api.publish_emotion(
f"#{post_id}"+self.ap.config.campux_publish_text_extra,
post.extra_text,
images_to_post
)

Expand Down
45 changes: 45 additions & 0 deletions campux/social/preproc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import annotations

import traceback
import re

from ..core import app
from ..common import entity


class PostPreprocessor:

def __init__(self, ap: app.Application):
self.ap = ap

async def preprocess_post(self, post: entity.Post) -> entity.Post:
"""预处理稿件"""
try:
post.extra_text = await self.emotion_text_preprocess(post)
except Exception as e:
traceback.print_exc()
post.extra_text = ''

return post

async def emotion_text_preprocess(self, post: entity.Post) -> str:
"""发表时的附带文本预处理"""

text = post.text
post_id = post.id
uin = str(post.uin)

def at(user_id):
return f"@{{uin:{user_id},nick:,who:1}}"

def links():
# 从 text 中提取链接
return re.findall(r'https?://[^\s]+', text)

extra_raw_text = self.ap.meta.data['post_publish_text']

extra_text = eval(extra_raw_text)

# exec(extra_raw_text, locals())

return extra_text

0 comments on commit 0a92c5d

Please sign in to comment.