Files
Mycontent/scripts/migrate_2026_sections.py
卡若 76965adb23 chore: 清理敏感与开发文档,仅同步代码
- 永久忽略并从仓库移除 开发文档/
- 移除并忽略 .env 与小程序私有配置
- 同步小程序/管理端/API与脚本改动

Made-with: Cursor
2026-03-17 17:50:12 +08:00

152 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
将第102场及以后的派对场次迁移到「2026每日派对干货」目录
用法:
python3 scripts/migrate_2026_sections.py # 仅预览,不执行
python3 scripts/migrate_2026_sections.py --execute # 执行迁移
迁移规则:
- 从章节中筛选 section_title 包含「第102场」「第103场」... 的条目
- 按场次号排序,依次赋 id 10.01, 10.02, 10.03, ...
- 更新 part_id=part-2026-daily, part_title=2026每日派对干货
- 更新 chapter_id=chapter-2026-daily, chapter_title=2026每日派对干货
依赖: pip install pymysql
"""
import argparse
import re
import sys
from pathlib import Path
# 项目根目录
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
try:
import pymysql
except ImportError:
print("需要安装 pymysql: pip3 install pymysql")
sys.exit(1)
DB_CONFIG = {
"host": "56b4c23f6853c.gz.cdb.myqcloud.com",
"port": 14413,
"user": "cdb_outerroot",
"password": "Zhiqun1984",
"database": "soul_miniprogram",
"charset": "utf8mb4",
}
PART_2026 = "part-2026-daily"
CHAPTER_2026 = "chapter-2026-daily"
TITLE_2026 = "2026每日派对干货"
def extract_session_num(section_title: str) -> int | None:
"""从 section_title 解析场次号,如 第102场 -> 102"""
m = re.search(r"第(\d+)场", section_title)
return int(m.group(1)) if m else None
def get_connection():
return pymysql.connect(**DB_CONFIG)
def get_max_10_section(cur) -> int:
"""获取当前 10.xx 最大序号"""
cur.execute(
"SELECT id FROM chapters WHERE id REGEXP '^10\\.[0-9]+$' ORDER BY CAST(SUBSTRING_INDEX(id, '.', -1) AS UNSIGNED) DESC LIMIT 1"
)
row = cur.fetchone()
if row:
return int(row[0].split(".")[-1])
return 0
def find_sections_to_migrate(cur) -> list[tuple]:
"""查找需要迁移的章节第102场及以后且不在 part-2026-daily 的"""
cur.execute("""
SELECT id, section_title, part_id, chapter_id, sort_order
FROM chapters
WHERE section_title REGEXP '第[0-9]+场'
ORDER BY sort_order, id
""")
rows = cur.fetchall()
to_migrate = []
for row in rows:
sid, title, part_id, ch_id, order = row
num = extract_session_num(title)
if num is not None and num >= 102 and part_id != PART_2026:
to_migrate.append((sid, title, part_id, ch_id, order, num))
to_migrate.sort(key=lambda x: (x[5], x[4])) # 按场次号、sort_order
return to_migrate
def run(dry_run: bool):
conn = get_connection()
cur = conn.cursor()
rows = find_sections_to_migrate(cur)
max_10 = get_max_10_section(cur)
conn.close()
if not rows:
print("未找到需要迁移的章节第102场及以后、且不在 2026每日派对干货 中)")
return
print(f"当前 10.xx 最大序号: {max_10}")
print(f"找到 {len(rows)} 节待迁移到「2026每日派对干货」\n")
plan = []
for i, (old_id, title, part_id, ch_id, order, num) in enumerate(rows, 1):
new_id = f"10.{max_10 + i:02d}"
plan.append((old_id, new_id, title, part_id))
print(f" {old_id} -> {new_id} {title}")
if dry_run:
print("\n[预览模式] 未执行写入,使用 --execute 执行迁移")
return
print("\n执行迁移...")
conn = get_connection()
cur = conn.cursor()
try:
# 先全部改为临时 id避免与已有 10.xx 冲突)
for i, (old_id, new_id, title, part_id) in enumerate(plan, 1):
tmp_id = f"tmp-migrate-{old_id.replace('.', '-')}"
cur.execute(
"UPDATE chapters SET id = %s WHERE id = %s",
(tmp_id, old_id),
)
conn.commit()
# 再改为最终 id 并更新 part/chapter
for i, (old_id, new_id, title, part_id) in enumerate(plan, 1):
tmp_id = f"tmp-migrate-{old_id.replace('.', '-')}"
cur.execute("""
UPDATE chapters SET
id = %s, part_id = %s, part_title = %s,
chapter_id = %s, chapter_title = %s
WHERE id = %s
""", (new_id, PART_2026, TITLE_2026, CHAPTER_2026, TITLE_2026, tmp_id))
conn.commit()
print(f"已迁移 {len(plan)} 节到 part-2026-dailyid 为 10.01 ~ 10.{len(plan):02d}")
except Exception as e:
conn.rollback()
print(f"迁移失败: {e}")
raise
finally:
conn.close()
def main():
parser = argparse.ArgumentParser(description="将第102场及以后的场次迁移到 2026每日派对干货")
parser.add_argument("--execute", action="store_true", help="执行迁移(默认仅预览)")
args = parser.parse_args()
run(dry_run=not args.execute)
if __name__ == "__main__":
main()