1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| """ Valine 到 Waline 评论数据转换脚本 将 Valine (LeanCloud) 导出的评论数据转换为 Waline 格式 """
import json import re from datetime import datetime
EMOTION_MAP = { 'whee': '😁', 'no way': '😱', 'clap': '👏', 'amorousness': '😍', 'longing': '🥺', 'love you': '😘', 'happy': '😊', 'tear': '😢', 'punch': '👊', }
def convert_emotions_to_emoji(text): """ 将 Valine 的表情符号语法 :emotion: 转换为对应的 emoji """ def replace_emotion(match): emotion_name = match.group(1).strip() return EMOTION_MAP.get(emotion_name, match.group(0)) return re.sub(r'(?<!https)(?<!http):([a-z\s]+):', replace_emotion, text)
def convert_valine_to_waline(valine_data): """ 将 Valine 格式的评论数据转换为 Waline 格式 主要字段映射: - objectId: 保持不变,作为评论的唯一标识 - comment: 评论内容,保持不变 - nick: 昵称,保持不变 - mail: 邮箱,保持不变 - link: 网站链接,保持不变 - ua: User Agent,保持不变 - ip: IP地址,保持不变 - url: 评论所在页面URL,保持不变 - pid: 父评论ID,保持不变 - rid: 根评论ID,保持不变 - createdAt/updatedAt/insertedAt: 时间字段,保持不变 新增字段(Waline特有): - user_id: 用户ID,设为null(匿名用户) - status: 评论状态,默认为"approved"(已批准) - sticky: 置顶标记,设为null - like: 点赞数,设为null - QQAvatar: Valine特有字段,不转换到Waline """ waline_comments = [] for valine_comment in valine_data: original_comment = valine_comment.get("comment", "") converted_comment = convert_emotions_to_emoji(original_comment) waline_comment = { "user_id": None, "comment": converted_comment, "ip": valine_comment.get("ip", ""), "link": valine_comment.get("link", ""), "mail": valine_comment.get("mail", ""), "nick": valine_comment.get("nick", "Anonymous"), "pid": valine_comment.get("pid"), "rid": valine_comment.get("rid"), "sticky": None, "status": "approved", "like": None, "ua": valine_comment.get("ua", ""), "url": valine_comment.get("url", "/"), "objectId": valine_comment.get("objectId", ""), "insertedAt": valine_comment.get("insertedAt", valine_comment.get("createdAt")), "createdAt": valine_comment.get("createdAt"), "updatedAt": valine_comment.get("updatedAt", valine_comment.get("createdAt")) } waline_comments.append(waline_comment) return waline_comments
def create_waline_export(comments): """ 创建完整的 Waline 导出格式 """ return { "__version": "1.39.3", "type": "waline", "version": 1, "time": int(datetime.now().timestamp() * 1000), "tables": ["Comment", "Counter", "Users"], "data": { "Comment": comments, "Counter": [], "Users": [] } }
def main(): with open('/home/tianlejin/myblog/test/Comment_20260313_085101.json', 'r', encoding='utf-8') as f: valine_data = json.load(f) print(f"读取到 {len(valine_data)} 条 Valine 评论") waline_comments = convert_valine_to_waline(valine_data) waline_export = create_waline_export(waline_comments) output_path = '/home/tianlejin/myblog/test/waline_output.json' with open(output_path, 'w', encoding='utf-8') as f: json.dump(waline_export, f, ensure_ascii=False, indent=2) print(f"转换完成!已生成 {len(waline_comments)} 条 Waline 评论") print(f"输出文件:{output_path}") urls = set(comment['url'] for comment in waline_comments) print(f"\n统计信息:") print(f"- 总评论数:{len(waline_comments)}") print(f"- 涉及页面数:{len(urls)}") replies = [c for c in waline_comments if c['pid'] is not None] print(f"- 回复评论数:{len(replies)}") print(f"- 顶级评论数:{len(waline_comments) - len(replies)}") emotion_count = sum(1 for c in valine_data if any(f':{e}:' in c.get('comment', '') for e in EMOTION_MAP.keys())) print(f"- 包含表情符号的评论数:{emotion_count}")
if __name__ == "__main__": main()
|