59 lines
2.5 KiB
Python
59 lines
2.5 KiB
Python
# -*- coding: utf-8 -*-
|
||
import os
|
||
import sys
|
||
import subprocess
|
||
import logging
|
||
from odoo import models, fields
|
||
from odoo.modules.module import get_module_path
|
||
|
||
_logger = logging.getLogger(__name__)
|
||
|
||
|
||
class GameStoryVolume(models.Model):
|
||
_name = 'game.story.volume'
|
||
_description = '小说卷'
|
||
_order = 'sequence, id'
|
||
_rec_name = 'name'
|
||
|
||
name = fields.Char(string='卷名', required=True, index=True)
|
||
sequence = fields.Integer(string='序号', default=10, index=True)
|
||
intro = fields.Html(string='卷首语')
|
||
chapter_ids = fields.One2many('game.story.chapter', 'volume_id', string='章节')
|
||
|
||
def action_sync_novel(self):
|
||
"""由定时任务(ir.cron)调用:把 novel/ 下的 Markdown 增量同步进数据库。
|
||
走独立同步脚本(novel/sync_novel.py),单一实现来源。
|
||
注意:脚本依赖 venv 的 psycopg2,而 Odoo 可能跑在系统 Python 上,
|
||
因此显式使用项目 venv 的 python 执行,而非 sys.executable。"""
|
||
base = get_module_path('game_base')
|
||
script = os.path.normpath(os.path.join(base, '..', '..', 'novel', 'sync_novel.py'))
|
||
if not os.path.exists(script):
|
||
_logger.warning('小说同步脚本不存在: %s', script)
|
||
return
|
||
# 优先用项目 venv 的 python(自带 psycopg2);否则退化为当前解释器
|
||
venv_py = os.path.normpath(os.path.join(base, '..', '..', '..', '.venv', 'Scripts', 'python.exe'))
|
||
python = venv_py if os.path.exists(venv_py) else sys.executable
|
||
try:
|
||
proc = subprocess.run([python, script],
|
||
capture_output=True, text=True, timeout=180)
|
||
if proc.returncode != 0:
|
||
_logger.error('小说同步失败(%s): %s', proc.returncode, (proc.stderr or '')[-2000:])
|
||
else:
|
||
last = (proc.stdout or '').strip().splitlines()
|
||
_logger.info('小说同步完成: %s', last[-1] if last else 'ok')
|
||
except Exception as e:
|
||
_logger.exception('小说同步异常: %s', e)
|
||
|
||
|
||
class GameStoryChapter(models.Model):
|
||
_name = 'game.story.chapter'
|
||
_description = '小说章节'
|
||
_order = 'volume_id, sequence, id'
|
||
_rec_name = 'name'
|
||
|
||
volume_id = fields.Many2one('game.story.volume', string='所属卷',
|
||
required=True, ondelete='cascade', index=True)
|
||
name = fields.Char(string='章名', required=True, index=True)
|
||
sequence = fields.Integer(string='序号', default=10, index=True)
|
||
body_html = fields.Html(string='正文')
|