diff --git a/.github/workflows/crawler.yml b/.github/workflows/crawler.yml index e7d4450..5714814 100644 --- a/.github/workflows/crawler.yml +++ b/.github/workflows/crawler.yml @@ -62,6 +62,7 @@ jobs: NTFY_TOPIC: ${{ secrets.NTFY_TOPIC }} NTFY_SERVER_URL: ${{ secrets.NTFY_SERVER_URL }} NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }} + BARK_URL: ${{ secrets.BARK_URL }} GITHUB_ACTIONS: true run: python main.py diff --git a/README-EN.md b/README-EN.md index 265f043..1c56aab 100644 --- a/README-EN.md +++ b/README-EN.md @@ -8,12 +8,13 @@ sansan0%2FTrendRadar | Trendshift -302.AI logo +302.AI logo +FlashSpeak logo [![GitHub Stars](https://img.shields.io/github/stars/sansan0/TrendRadar?style=flat-square&logo=github&color=yellow)](https://github.com/sansan0/TrendRadar/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/sansan0/TrendRadar?style=flat-square&logo=github&color=blue)](https://github.com/sansan0/TrendRadar/network/members) [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](LICENSE) -[![Version](https://img.shields.io/badge/version-v3.2.0-blue.svg)](https://github.com/sansan0/TrendRadar) +[![Version](https://img.shields.io/badge/version-v3.3.0-blue.svg)](https://github.com/sansan0/TrendRadar) [![MCP](https://img.shields.io/badge/MCP-v1.0.2-green.svg)](https://github.com/sansan0/TrendRadar) [![WeWork](https://img.shields.io/badge/WeWork-Notification-00D4AA?style=flat-square)](https://work.weixin.qq.com/) @@ -258,11 +259,35 @@ Transform from "algorithm recommendation captivity" to "actively getting the inf ## 📝 Changelog >**Upgrade Instructions**: -- **Tip**: Do NOT update this project via **Sync fork**. Check [Changelog](#changelog) to understand specific [Upgrade Methods] and [Features] +- **📌 Check Latest Updates**: **[Original Repository Changelog](https://github.com/sansan0/TrendRadar?tab=readme-ov-file#-changelog)** +- **Tip**: Do NOT update this project via **Sync fork**. Check [Changelog] to understand specific [Upgrade Methods] and [Features] - **Minor Version Update**: Upgrading from v2.x to v2.y, replace `main.py` in your forked repo with the latest version - **Major Version Upgrade**: Upgrading from v1.x to v2.y, recommend deleting existing fork and re-forking to save effort and avoid config conflicts +### 2025/11/24 - v3.3.0 + +**🎉 Added Bark Push Support** + +1. **iOS Exclusive Push Channel** + - Supports Bark push (based on APNs, iOS platform) + - Free, open-source, clean, efficient, ad-free + - Supports both official server and self-hosted server + +2. **Multiple Deployment Methods** + - GitHub Actions: Configure `BARK_URL` Secret + - Docker: Environment variable `BARK_URL` + - Local: `config/config.yaml` configuration file + +> 📖 **Detailed Configuration Tutorial**: [Quick Start - Bark Push](#-quick-start) + +**🐛 Bug Fix** +- Fixed issue where `ntfy_server_url` in `config.yaml` was ignored ([#345](https://github.com/sansan0/TrendRadar/issues/345)) + +**🔧 Upgrade Instructions**: +- **GitHub Fork Users**: Update `main.py`, `config/config.yaml`, `.github/workflows/crawler.yml` + + ### 2025/11/23 - v3.2.0 **🎯 New Advanced Customization Features** @@ -2078,23 +2103,19 @@ Any client supporting Model Context Protocol can connect to TrendRadar: ## 🪄 Sponsors +### 🤖 302.AI - Enterprise AI Resource Platform + > **302.AI** is a pay-as-you-go enterprise-level AI resource platform > Providing the latest and most comprehensive **AI models** and **APIs** on the market, plus various ready-to-use online AI applications -
+[![Register & Claim](https://img.shields.io/badge/Register_302.AI-Claim_$1_Credit-8B5CF6?style=for-the-badge&logo=openai&logoColor=white)](https://share.302.ai/mEOUzG) - 302.AI + 302.AI
-### 💰 302.AI New User Benefits - -> The $1 credit can be used to call various AI models (such as Claude, GPT, etc.) -> This project's AI analysis features require AI model integration. See [AI Analysis Deployment](#-ai-analysis-deployment) for configuration tutorial - -[![Register & Claim](https://img.shields.io/badge/Register_302.AI-Claim_$1_Free_Credit-FF6B6B?style=for-the-badge&logo=openai&logoColor=white)](https://share.302.ai/mEOUzG) -
+ +> Tracking so many trending topics daily, writing reports, replying messages making your wrists tired? +> +> Try「FlashSpeak」AI Voice Input - Speak instead of type, 4x faster ⚡ +> +> On-device Model • Lightning Fast • Absolute Privacy • Mac/Win Support +> +> From reading trends to content output, double your efficiency 👇 + +
+ +[![Mac Download](https://img.shields.io/badge/Mac-Free_Download-FF6B6B?style=for-the-badge&logo=apple&logoColor=white)](https://shandianshuo.cn) [![Windows Download](https://img.shields.io/badge/Windows-Free_Download-FF6B6B?style=for-the-badge&logo=lightning&logoColor=white)](https://shandianshuo.cn) + + FlashSpeak + +
+ + --- diff --git a/README.md b/README.md index ef605d1..489986d 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,20 @@
- TrendRadar Banner + TrendRadar Banner 🚀 最快30秒部署的热点助手 —— 告别无效刷屏,只看真正关心的新闻资讯 sansan0%2FTrendRadar | Trendshift -302.AI logo +302.AI logo +闪电说 logo [![GitHub Stars](https://img.shields.io/github/stars/sansan0/TrendRadar?style=flat-square&logo=github&color=yellow)](https://github.com/sansan0/TrendRadar/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/sansan0/TrendRadar?style=flat-square&logo=github&color=blue)](https://github.com/sansan0/TrendRadar/network/members) [![License](https://img.shields.io/badge/license-GPL--3.0-blue.svg?style=flat-square)](LICENSE) -[![Version](https://img.shields.io/badge/version-v3.2.0-blue.svg)](https://github.com/sansan0/TrendRadar) +[![Version](https://img.shields.io/badge/version-v3.3.0-blue.svg)](https://github.com/sansan0/TrendRadar) [![MCP](https://img.shields.io/badge/MCP-v1.0.2-green.svg)](https://github.com/sansan0/TrendRadar) [![企业微信通知](https://img.shields.io/badge/企业微信-通知-00D4AA?style=flat-square)](https://work.weixin.qq.com/) @@ -327,6 +328,33 @@ GitHub 一键 Fork 即可使用,无需编程基础。 - **大版本升级**:从 v1.x 升级到 v2.y,建议删除现有 fork 后重新 fork,这样更省力且避免配置冲突 +### 2025/11/24 - v3.3.0 + +**🎉 新增 Bark 推送支持** + +1. **iOS 专属推送渠道** + - 支持 Bark 推送(基于 APNs,iOS 平台) + - 免费开源,简洁高效,无广告干扰 + - 支持官方服务器和自建服务器两种方式 + +2. **多种部署方式** + - GitHub Actions:配置 `BARK_URL` Secret + - Docker:环境变量 `BARK_URL` + - 本地运行:`config/config.yaml` 配置文件 + +> 📖 **详细配置教程**:[快速开始 - Bark 推送](#-快速开始) + +**🐛 Bug 修复** +- 修复 `config.yaml` 中 `ntfy_server_url` 配置不生效的问题 ([#345](https://github.com/sansan0/TrendRadar/issues/345)) + +**🔧 升级说明**: +- **GitHub Fork 用户**:更新 `main.py`、`config/config.yaml`、`.github/workflows/crawler.yml` + + +
+👉 点击展开:历史更新 + + ### 2025/11/23 - v3.2.0 **🎯 新增高级定制功能** @@ -351,10 +379,6 @@ GitHub 一键 Fork 即可使用,无需编程基础。 - 优化查询今日新闻却可能错误返回过去日期的情况 -
-👉 点击展开:历史更新 - - ### 2025/11/22 - v3.1.1 - **修复数据异常导致的崩溃问题**:解决部分用户在 GitHub Actions 环境中遇到的 `'float' object has no attribute 'lower'` 错误 @@ -938,6 +962,7 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号 | **新浪邮箱** | sina.com | smtp.sina.com | 465 | SSL | | **搜狐邮箱** | sohu.com | smtp.sohu.com | 465 | SSL | | **天翼邮箱** | 189.cn | smtp.189.cn | 465 | SSL | + | **阿里云邮箱** | aliyun.com | smtp.aliyun.com | 465 | TLS | > **自动识别**:使用以上邮箱时,无需手动配置 `EMAIL_SMTP_SERVER` 和 `EMAIL_SMTP_PORT`,系统会自动识别。 > @@ -947,6 +972,7 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号 > > **特别感谢**: > - 感谢 [@DYZYD](https://github.com/DYZYD) 贡献天翼邮箱(189.cn)配置并完成自发自收测试 ([#291](https://github.com/sansan0/TrendRadar/issues/291)) + > - 感谢 [@longzhenren](https://github.com/longzhenren) 贡献阿里云邮箱(aliyun.com)配置并完成测试 ([#344](https://github.com/sansan0/TrendRadar/issues/344)) **常见邮箱设置:** @@ -1098,6 +1124,64 @@ frequency_words.txt 文件增加了一个【必须词】功能,使用 + 号
+
+ 👉 点击展开:Bark 推送(iOS 专属,简洁高效) +
+ + **GitHub Secret 配置(⚠️ Name 名称必须严格一致):** + - **Name(名称)**:`BARK_URL`(请复制粘贴此名称,不要手打) + - **Secret(值)**:你的 Bark 推送 URL + +
+ + **Bark 简介:** + + Bark 是一款 iOS 平台的免费开源推送工具,特点是简单、快速、无广告。 + + **使用方式:** + + ### 方式一:使用官方服务器(推荐新手) 🆓 + + 1. **下载 Bark App**: + - iOS:[App Store](https://apps.apple.com/cn/app/bark-给你的手机发推送/id1403753865) + + 2. **获取推送 URL**: + - 打开 Bark App + - 复制首页显示的推送 URL(格式如:`https://api.day.app/your_device_key`) + - 将 URL 配置到 GitHub Secrets 中的 `BARK_URL` + + ### 方式二:自建服务器(完全隐私控制) 🔒 + + **适合人群**:有服务器、追求完全隐私、技术能力强 + + **Docker 一键部署**: + ```bash + docker run -d \ + --name bark-server \ + -p 8080:8080 \ + finab/bark-server + ``` + + **配置 TrendRadar**: + ```yaml + BARK_URL: http://your-server-ip:8080/your_device_key + ``` + + --- + + **注意事项:** + - ✅ Bark 使用 APNs 推送,单条消息最大 4KB + - ✅ 支持自动分批推送,无需担心消息过长 + - ✅ 推送格式为纯文本(自动去除 Markdown 语法) + - ⚠️ 仅支持 iOS 平台 + + **相关链接:** + - [Bark 官方网站](https://bark.day.app/) + - [Bark GitHub 仓库](https://github.com/Finb/Bark) + - [Bark Server 自建教程](https://github.com/Finb/bark-server) + +
+ 3. **手动测试新闻推送**: > 💡 **完成第1-2步后,请立即测试!** 测试成功后再根据需要调整配置(第4步)。 @@ -2206,21 +2290,19 @@ MCP Inspector 是官方调试工具,用于测试 MCP 连接:
+[![注册领取](https://img.shields.io/badge/注册_302.AI-领取_1_美元免费测试额度-8B5CF6?style=for-the-badge&logo=openai&logoColor=white)](https://share.302.ai/mEOUzG) - 302.AI + 302.AI
-### 💰 302.AI 新用户福利 - -> 领取的 1 美元可用于调用各种 AI 大模型(如 Claude、GPT 等) -> 本项目 AI 分析功能需配置大模型使用,配置教程详见 [AI 智能分析](#-ai-智能分析) - -[![注册领取](https://img.shields.io/badge/注册_302.AI-领取_1_美元免费测试额度-FF6B6B?style=for-the-badge&logo=openai&logoColor=white)](https://share.302.ai/mEOUzG) ---- -
+> 每天追踪这么多热点,写报告、回复消息是否让手腕疲惫? +> 试试「闪电说」AI 语音输入法 —— 用说的,比打字快 4 倍 ⚡ 。从看热点到输出内容,让效率翻倍 👇 + +
+ +[![Mac下载](https://img.shields.io/badge/Mac-免费下载-FF6B6B?style=for-the-badge&logo=apple&logoColor=white)](https://shandianshuo.cn) [![Windows下载](https://img.shields.io/badge/Windows-免费下载-FF6B6B?style=for-the-badge&logo=lightning&logoColor=white)](https://shandianshuo.cn) + + 闪电说 + +
+ + + +--- ### 项目相关 @@ -2342,4 +2436,4 @@ GPL-3.0 License [🔝 回到顶部](#trendradar) -
+ \ No newline at end of file diff --git a/_image/ai3.png b/_image/ai3.png index ee77a6b..728c1bd 100644 Binary files a/_image/ai3.png and b/_image/ai3.png differ diff --git a/_image/banner-shandianshuo.png b/_image/banner-shandianshuo.png new file mode 100644 index 0000000..94ad566 Binary files /dev/null and b/_image/banner-shandianshuo.png differ diff --git a/_image/shandianshuo.png b/_image/shandianshuo.png new file mode 100644 index 0000000..3c1039f Binary files /dev/null and b/_image/shandianshuo.png differ diff --git a/config/config.yaml b/config/config.yaml index c53fde6..8441807 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -35,6 +35,7 @@ notification: message_batch_size: 4000 # 消息分批大小(字节)(这个配置别动) dingtalk_batch_size: 20000 # 钉钉消息分批大小(字节)(这个配置也别动) feishu_batch_size: 29000 # 飞书消息分批大小(字节) + bark_batch_size: 3600 # Bark消息分批大小(字节) batch_send_interval: 3 # 批次发送间隔(秒) feishu_message_separator: "━━━━━━━━━━━━━━━━━━━" # feishu 消息分割线 @@ -84,6 +85,7 @@ notification: ntfy_server_url: "https://ntfy.sh" # ntfy服务器地址,默认使用公共服务,可改为自托管地址 ntfy_topic: "" # ntfy主题名称 ntfy_token: "" # ntfy访问令牌(可选,用于私有主题) + bark_url: "" # Bark推送URL(格式:https://api.day.app/your_device_key 或自建服务器地址) # 用于让关注度更高的新闻在更前面显示,即用算法重新组合不同平台的热搜排序形成你侧重的热搜,合起来是 1 就行 weight: diff --git a/docker/docker-compose-build.yml b/docker/docker-compose-build.yml index bff1995..c241068 100644 --- a/docker/docker-compose-build.yml +++ b/docker/docker-compose-build.yml @@ -41,6 +41,8 @@ services: - NTFY_SERVER_URL=${NTFY_SERVER_URL:-https://ntfy.sh} - NTFY_TOPIC=${NTFY_TOPIC:-} - NTFY_TOKEN=${NTFY_TOKEN:-} + # Bark配置 + - BARK_URL=${BARK_URL:-} # 运行模式 - CRON_SCHEDULE=${CRON_SCHEDULE:-*/5 * * * *} - RUN_MODE=${RUN_MODE:-cron} diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 4ba55e1..6124cfc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -39,6 +39,8 @@ services: - NTFY_SERVER_URL=${NTFY_SERVER_URL:-https://ntfy.sh} - NTFY_TOPIC=${NTFY_TOPIC:-} - NTFY_TOKEN=${NTFY_TOKEN:-} + # Bark配置 + - BARK_URL=${BARK_URL:-} # 运行模式 - CRON_SCHEDULE=${CRON_SCHEDULE:-*/5 * * * *} - RUN_MODE=${RUN_MODE:-cron} diff --git a/main.py b/main.py index c722454..62d12dd 100644 --- a/main.py +++ b/main.py @@ -20,7 +20,7 @@ import requests import yaml -VERSION = "3.2.0" +VERSION = "3.3.0" # === SMTP邮件配置 === @@ -50,6 +50,8 @@ SMTP_CONFIGS = { "sohu.com": {"server": "smtp.sohu.com", "port": 465, "encryption": "SSL"}, # 天翼邮箱(使用 SSL) "189.cn": {"server": "smtp.189.cn", "port": 465, "encryption": "SSL"}, + # 阿里云邮箱(使用 TLS) + "aliyun.com": {"server": "smtp.aliyun.com", "port": 465, "encryption": "TLS"}, } @@ -97,6 +99,7 @@ def load_config(): "dingtalk_batch_size", 20000 ), "FEISHU_BATCH_SIZE": config_data["notification"].get("feishu_batch_size", 29000), + "BARK_BATCH_SIZE": config_data["notification"].get("bark_batch_size", 3600), "BATCH_SEND_INTERVAL": config_data["notification"]["batch_send_interval"], "FEISHU_MESSAGE_SEPARATOR": config_data["notification"][ "feishu_message_separator" @@ -182,9 +185,11 @@ def load_config(): ).strip() or webhooks.get("email_smtp_port", "") # ntfy配置 - config["NTFY_SERVER_URL"] = os.environ.get( - "NTFY_SERVER_URL", "https://ntfy.sh" - ).strip() or webhooks.get("ntfy_server_url", "https://ntfy.sh") + config["NTFY_SERVER_URL"] = ( + os.environ.get("NTFY_SERVER_URL", "").strip() + or webhooks.get("ntfy_server_url") + or "https://ntfy.sh" + ) config["NTFY_TOPIC"] = os.environ.get("NTFY_TOPIC", "").strip() or webhooks.get( "ntfy_topic", "" ) @@ -192,6 +197,11 @@ def load_config(): "ntfy_token", "" ) + # Bark配置 + config["BARK_URL"] = os.environ.get("BARK_URL", "").strip() or webhooks.get( + "bark_url", "" + ) + # 输出配置来源信息 notification_sources = [] if config["FEISHU_WEBHOOK_URL"]: @@ -217,6 +227,10 @@ def load_config(): server_source = "环境变量" if os.environ.get("NTFY_SERVER_URL") else "配置文件" notification_sources.append(f"ntfy({server_source})") + if config["BARK_URL"]: + bark_source = "环境变量" if os.environ.get("BARK_URL") else "配置文件" + notification_sources.append(f"Bark({bark_source})") + if notification_sources: print(f"通知渠道配置来源: {', '.join(notification_sources)}") else: @@ -3397,6 +3411,7 @@ def send_to_notifications( ntfy_server_url = CONFIG["NTFY_SERVER_URL"] ntfy_topic = CONFIG["NTFY_TOPIC"] ntfy_token = CONFIG.get("NTFY_TOKEN", "") + bark_url = CONFIG["BARK_URL"] update_info_to_send = update_info if CONFIG["SHOW_VERSION_UPDATE"] else None @@ -3443,6 +3458,17 @@ def send_to_notifications( mode, ) + # 发送到 Bark + if bark_url: + results["bark"] = send_to_bark( + bark_url, + report_data, + report_type, + update_info_to_send, + proxy_url, + mode, + ) + # 发送邮件 if email_from and email_password and email_to: results["email"] = send_to_email( @@ -4129,6 +4155,116 @@ def send_to_ntfy( return False +def send_to_bark( + bark_url: str, + report_data: Dict, + report_type: str, + update_info: Optional[Dict] = None, + proxy_url: Optional[str] = None, + mode: str = "daily", +) -> bool: + """发送到Bark(支持分批发送,使用纯文本格式)""" + proxies = None + if proxy_url: + proxies = {"http": proxy_url, "https": proxy_url} + + # 获取分批内容(Bark 限制为 3600 字节以避免 413 错误) + batches = split_content_into_batches( + report_data, "wework", update_info, max_bytes=CONFIG["BARK_BATCH_SIZE"], mode=mode + ) + + total_batches = len(batches) + print(f"Bark消息分为 {total_batches} 批次发送 [{report_type}]") + + # 反转批次顺序,使得在Bark客户端显示时顺序正确 + # Bark显示最新消息在上面,所以我们从最后一批开始推送 + reversed_batches = list(reversed(batches)) + + print(f"Bark将按反向顺序推送(最后批次先推送),确保客户端显示顺序正确") + + # 逐批发送(反向顺序) + success_count = 0 + for idx, batch_content in enumerate(reversed_batches, 1): + # 计算正确的批次编号(用户视角的编号) + actual_batch_num = total_batches - idx + 1 + + # 添加批次标识(使用正确的批次编号) + if total_batches > 1: + batch_header = f"[第 {actual_batch_num}/{total_batches} 批次]\n\n" + batch_content = batch_header + batch_content + + # 清理 markdown 语法(Bark 不支持 markdown) + plain_content = strip_markdown(batch_content) + + batch_size = len(plain_content.encode("utf-8")) + print( + f"发送Bark第 {actual_batch_num}/{total_batches} 批次(推送顺序: {idx}/{total_batches}),大小:{batch_size} 字节 [{report_type}]" + ) + + # 检查消息大小(Bark使用APNs,限制4KB) + if batch_size > 4096: + print( + f"警告:Bark第 {actual_batch_num}/{total_batches} 批次消息过大({batch_size} 字节),可能被拒绝" + ) + + # 构建JSON payload + payload = { + "title": report_type, + "body": plain_content, + "sound": "default", + "group": "TrendRadar", + } + + try: + response = requests.post( + bark_url, + json=payload, + proxies=proxies, + timeout=30, + ) + + if response.status_code == 200: + result = response.json() + if result.get("code") == 200: + print(f"Bark第 {actual_batch_num}/{total_batches} 批次发送成功 [{report_type}]") + success_count += 1 + # 批次间间隔 + if idx < total_batches: + time.sleep(CONFIG["BATCH_SEND_INTERVAL"]) + else: + print( + f"Bark第 {actual_batch_num}/{total_batches} 批次发送失败 [{report_type}],错误:{result.get('message', '未知错误')}" + ) + else: + print( + f"Bark第 {actual_batch_num}/{total_batches} 批次发送失败 [{report_type}],状态码:{response.status_code}" + ) + try: + print(f"错误详情:{response.text}") + except: + pass + + except requests.exceptions.ConnectTimeout: + print(f"Bark第 {actual_batch_num}/{total_batches} 批次连接超时 [{report_type}]") + except requests.exceptions.ReadTimeout: + print(f"Bark第 {actual_batch_num}/{total_batches} 批次读取超时 [{report_type}]") + except requests.exceptions.ConnectionError as e: + print(f"Bark第 {actual_batch_num}/{total_batches} 批次连接错误 [{report_type}]:{e}") + except Exception as e: + print(f"Bark第 {actual_batch_num}/{total_batches} 批次发送异常 [{report_type}]:{e}") + + # 判断整体发送是否成功 + if success_count == total_batches: + print(f"Bark所有 {total_batches} 批次发送完成 [{report_type}]") + return True + elif success_count > 0: + print(f"Bark部分发送成功:{success_count}/{total_batches} 批次 [{report_type}]") + return True # 部分成功也视为成功 + else: + print(f"Bark发送完全失败 [{report_type}]") + return False + + # === 主分析器 === class NewsAnalyzer: """新闻分析器""" @@ -4241,6 +4377,7 @@ class NewsAnalyzer: and CONFIG["EMAIL_TO"] ), (CONFIG["NTFY_SERVER_URL"] and CONFIG["NTFY_TOPIC"]), + CONFIG["BARK_URL"], ] ) diff --git a/version b/version index a4f52a5..0fa4ae4 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.2.0 \ No newline at end of file +3.3.0 \ No newline at end of file