This commit is contained in:
Your Name
2026-08-27 18:32:03 +08:00
parent 4ac6990efe
commit 1f3addcf79
50 changed files with 9145 additions and 1760 deletions
+40 -2
View File
@@ -53,12 +53,42 @@ def add_index_if_missing(
conn.execute(text(f"CREATE INDEX {index_name} ON {table} ({safe_columns})"))
def widen_mysql_text_columns(conn, table: str, columns: tuple[str, ...]) -> None:
"""Upgrade large account payloads from TEXT to LONGTEXT on MySQL.
SQLite and PostgreSQL TEXT values are not limited to 64 KiB, while MySQL
TEXT is. Browser storage_state and full-page QR/captcha screenshots can
legitimately exceed that size.
"""
if _dialect(conn) != "mysql":
return
allowed = {"cookie_data", "im_session_data", "qr_code_base64"}
try:
reflected = {
item["name"]: str(item.get("type") or "").upper()
for item in inspect(conn).get_columns(table)
}
except Exception:
return
for column in columns:
if column not in allowed or column not in reflected:
continue
if reflected[column] == "LONGTEXT":
continue
conn.execute(
text(f"ALTER TABLE {table} MODIFY COLUMN {column} LONGTEXT NULL")
)
def migrate_accounts_table(conn) -> None:
add_column_if_missing(
conn,
"accounts",
"cookie_data",
{"default": "ALTER TABLE accounts ADD COLUMN cookie_data TEXT"},
{
"default": "ALTER TABLE accounts ADD COLUMN cookie_data TEXT",
"mysql": "ALTER TABLE accounts ADD COLUMN cookie_data LONGTEXT",
},
)
add_column_if_missing(
conn,
@@ -73,7 +103,10 @@ def migrate_accounts_table(conn) -> None:
conn,
"accounts",
"im_session_data",
{"default": "ALTER TABLE accounts ADD COLUMN im_session_data TEXT"},
{
"default": "ALTER TABLE accounts ADD COLUMN im_session_data TEXT",
"mysql": "ALTER TABLE accounts ADD COLUMN im_session_data LONGTEXT",
},
)
add_column_if_missing(
conn,
@@ -138,6 +171,11 @@ def migrate_accounts_table(conn) -> None:
"douyin_uid",
{"default": "ALTER TABLE accounts ADD COLUMN douyin_uid VARCHAR(64)"},
)
widen_mysql_text_columns(
conn,
"accounts",
("cookie_data", "im_session_data", "qr_code_base64"),
)
def migrate_account_videos_table(conn) -> None:
+4 -3
View File
@@ -1,5 +1,6 @@
from datetime import datetime
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey, Index, Text, UniqueConstraint
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import relationship, validates
from .database import Base
from utils.log_limits import bound_error_log_content, bound_message_log_content
@@ -108,9 +109,9 @@ class Account(Base):
phone = Column(String(20), nullable=True) # 绑定的手机号(可选)
status = Column(String(50), default="offline") # offline, logging_in, online, error
cookie_path = Column(String(255), nullable=True) # 存储 cookie/session 的路径
cookie_data = Column(Text, nullable=True) # Playwright storage_state JSON
cookie_data = Column(Text().with_variant(LONGTEXT(), "mysql"), nullable=True) # Playwright storage_state JSON
cookie_updated_at = Column(DateTime, nullable=True) # Cookie 最近更新时间
im_session_data = Column(Text, nullable=True) # IM 直连会话 (WS URL / device_id 等)
im_session_data = Column(Text().with_variant(LONGTEXT(), "mysql"), nullable=True) # IM 直连会话 (WS URL / device_id 等)
reply_delay_seconds = Column(Integer, default=0) # 账号回复排队间隔;0/NULL=继承系统默认
reply_cooldown_seconds = Column(Integer, nullable=True) # 自动回复冷却秒数;NULL=继承全局设置
follow_welcome_enabled = Column(Boolean, default=False) # 新粉丝关注后自动发送欢迎语
@@ -118,7 +119,7 @@ class Account(Base):
user_agent = Column(Text, nullable=True) # 伪装设备头(User-Agent),空=默认
egress_public_ip = Column(String(64), nullable=True) # 指定公网出口;空=自动选择
egress_auto_attempts = Column(Integer, nullable=False, default=1) # 发送失败时最多串行尝试的出口数
qr_code_base64 = Column(Text, nullable=True) # 当前登录二维码的 base64 字符串
qr_code_base64 = Column(Text().with_variant(LONGTEXT(), "mysql"), nullable=True) # 当前登录二维码的 base64 字符串
error_message = Column(Text, nullable=True) # 错误信息
quota_disabled = Column(Boolean, default=False, index=True) # 额度不足被停用
created_at = Column(DateTime, default=datetime.utcnow)