formatter.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. # coding=utf-8
  2. """
  3. 平台标题格式化模块
  4. 提供多平台标题格式化功能
  5. """
  6. from typing import Dict
  7. from trendradar.report.helpers import clean_title, html_escape, format_rank_display
  8. def format_title_for_platform(
  9. platform: str, title_data: Dict, show_source: bool = True
  10. ) -> str:
  11. """统一的标题格式化方法
  12. 为不同平台生成对应格式的标题字符串。
  13. Args:
  14. platform: 目标平台,支持:
  15. - "feishu": 飞书
  16. - "dingtalk": 钉钉
  17. - "wework": 企业微信
  18. - "bark": Bark
  19. - "telegram": Telegram
  20. - "ntfy": ntfy
  21. - "slack": Slack
  22. - "html": HTML 报告
  23. title_data: 标题数据字典,包含以下字段:
  24. - title: 标题文本
  25. - source_name: 来源名称
  26. - time_display: 时间显示
  27. - count: 出现次数
  28. - ranks: 排名列表
  29. - rank_threshold: 高亮阈值
  30. - url: PC端链接
  31. - mobile_url: 移动端链接(优先使用)
  32. - is_new: 是否为新增标题(可选)
  33. show_source: 是否显示来源名称
  34. Returns:
  35. 格式化后的标题字符串
  36. """
  37. rank_display = format_rank_display(
  38. title_data["ranks"], title_data["rank_threshold"], platform
  39. )
  40. link_url = title_data["mobile_url"] or title_data["url"]
  41. cleaned_title = clean_title(title_data["title"])
  42. if platform == "feishu":
  43. if link_url:
  44. formatted_title = f"[{cleaned_title}]({link_url})"
  45. else:
  46. formatted_title = cleaned_title
  47. title_prefix = "🆕 " if title_data.get("is_new") else ""
  48. if show_source:
  49. result = f"<font color='grey'>[{title_data['source_name']}]</font> {title_prefix}{formatted_title}"
  50. else:
  51. result = f"{title_prefix}{formatted_title}"
  52. if rank_display:
  53. result += f" {rank_display}"
  54. if title_data["time_display"]:
  55. result += f" <font color='grey'>- {title_data['time_display']}</font>"
  56. if title_data["count"] > 1:
  57. result += f" <font color='green'>({title_data['count']}次)</font>"
  58. return result
  59. elif platform == "dingtalk":
  60. if link_url:
  61. formatted_title = f"[{cleaned_title}]({link_url})"
  62. else:
  63. formatted_title = cleaned_title
  64. title_prefix = "🆕 " if title_data.get("is_new") else ""
  65. if show_source:
  66. result = f"[{title_data['source_name']}] {title_prefix}{formatted_title}"
  67. else:
  68. result = f"{title_prefix}{formatted_title}"
  69. if rank_display:
  70. result += f" {rank_display}"
  71. if title_data["time_display"]:
  72. result += f" - {title_data['time_display']}"
  73. if title_data["count"] > 1:
  74. result += f" ({title_data['count']}次)"
  75. return result
  76. elif platform in ("wework", "bark"):
  77. # WeWork 和 Bark 使用 markdown 格式
  78. if link_url:
  79. formatted_title = f"[{cleaned_title}]({link_url})"
  80. else:
  81. formatted_title = cleaned_title
  82. title_prefix = "🆕 " if title_data.get("is_new") else ""
  83. if show_source:
  84. result = f"[{title_data['source_name']}] {title_prefix}{formatted_title}"
  85. else:
  86. result = f"{title_prefix}{formatted_title}"
  87. if rank_display:
  88. result += f" {rank_display}"
  89. if title_data["time_display"]:
  90. result += f" - {title_data['time_display']}"
  91. if title_data["count"] > 1:
  92. result += f" ({title_data['count']}次)"
  93. return result
  94. elif platform == "telegram":
  95. if link_url:
  96. formatted_title = f'<a href="{link_url}">{html_escape(cleaned_title)}</a>'
  97. else:
  98. formatted_title = cleaned_title
  99. title_prefix = "🆕 " if title_data.get("is_new") else ""
  100. if show_source:
  101. result = f"[{title_data['source_name']}] {title_prefix}{formatted_title}"
  102. else:
  103. result = f"{title_prefix}{formatted_title}"
  104. if rank_display:
  105. result += f" {rank_display}"
  106. if title_data["time_display"]:
  107. result += f" <code>- {title_data['time_display']}</code>"
  108. if title_data["count"] > 1:
  109. result += f" <code>({title_data['count']}次)</code>"
  110. return result
  111. elif platform == "ntfy":
  112. if link_url:
  113. formatted_title = f"[{cleaned_title}]({link_url})"
  114. else:
  115. formatted_title = cleaned_title
  116. title_prefix = "🆕 " if title_data.get("is_new") else ""
  117. if show_source:
  118. result = f"[{title_data['source_name']}] {title_prefix}{formatted_title}"
  119. else:
  120. result = f"{title_prefix}{formatted_title}"
  121. if rank_display:
  122. result += f" {rank_display}"
  123. if title_data["time_display"]:
  124. result += f" `- {title_data['time_display']}`"
  125. if title_data["count"] > 1:
  126. result += f" `({title_data['count']}次)`"
  127. return result
  128. elif platform == "slack":
  129. # Slack 使用 mrkdwn 格式
  130. if link_url:
  131. # Slack 链接格式: <url|text>
  132. formatted_title = f"<{link_url}|{cleaned_title}>"
  133. else:
  134. formatted_title = cleaned_title
  135. title_prefix = "🆕 " if title_data.get("is_new") else ""
  136. if show_source:
  137. result = f"[{title_data['source_name']}] {title_prefix}{formatted_title}"
  138. else:
  139. result = f"{title_prefix}{formatted_title}"
  140. # 排名(使用 * 加粗)
  141. rank_display = format_rank_display(
  142. title_data["ranks"], title_data["rank_threshold"], "slack"
  143. )
  144. if rank_display:
  145. result += f" {rank_display}"
  146. if title_data["time_display"]:
  147. result += f" `- {title_data['time_display']}`"
  148. if title_data["count"] > 1:
  149. result += f" `({title_data['count']}次)`"
  150. return result
  151. elif platform == "html":
  152. rank_display = format_rank_display(
  153. title_data["ranks"], title_data["rank_threshold"], "html"
  154. )
  155. link_url = title_data["mobile_url"] or title_data["url"]
  156. escaped_title = html_escape(cleaned_title)
  157. escaped_source_name = html_escape(title_data["source_name"])
  158. if link_url:
  159. escaped_url = html_escape(link_url)
  160. formatted_title = f'[{escaped_source_name}] <a href="{escaped_url}" target="_blank" class="news-link">{escaped_title}</a>'
  161. else:
  162. formatted_title = (
  163. f'[{escaped_source_name}] <span class="no-link">{escaped_title}</span>'
  164. )
  165. if rank_display:
  166. formatted_title += f" {rank_display}"
  167. if title_data["time_display"]:
  168. escaped_time = html_escape(title_data["time_display"])
  169. formatted_title += f" <font color='grey'>- {escaped_time}</font>"
  170. if title_data["count"] > 1:
  171. formatted_title += f" <font color='green'>({title_data['count']}次)</font>"
  172. if title_data.get("is_new"):
  173. formatted_title = f"<div class='new-title'>🆕 {formatted_title}</div>"
  174. return formatted_title
  175. else:
  176. return cleaned_title