feat: 添加 rsshub (#1232)

This commit is contained in:
himawari
2025-10-07 12:39:16 +08:00
committed by GitHub
parent a74bcb869a
commit aafac8d6fa
12 changed files with 1198 additions and 0 deletions

134
plugin/rsshub/domain/job.go Normal file
View File

@@ -0,0 +1,134 @@
// Package domain rsshub领域逻辑
package domain
import (
"context"
"github.com/mmcdole/gofeed"
"github.com/sirupsen/logrus"
)
// syncRss 同步所有频道
// 返回:更新的频道&订阅信息 map[int64]*RssClientView
// 1. 获取所有频道
// 2. 遍历所有频道,检查频道是否更新
// 3. 如果更新,获取更新的内容,但是返回的数据
func (repo *RssDomain) syncRss(ctx context.Context) (updated map[int64]*RssClientView, err error) {
updated = make(map[int64]*RssClientView)
// 获取所有频道
sources, err := repo.storage.GetSources(ctx)
if err != nil {
return
}
// 遍历所有源获取每个channel对应的rss内容
rssView := make([]*RssClientView, len(sources))
for i, channel := range sources {
var feed *gofeed.Feed
// 从site获取rss内容
feed, err = repo.rssHubClient.FetchFeed(channel.RssHubFeedPath)
// 如果获取失败,则跳过
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] fetch path(%+v) error: %v", channel.RssHubFeedPath, err)
continue
}
rv := convertFeedToRssView(0, channel.RssHubFeedPath, feed)
rssView[i] = rv
}
// 检查频道是否更新
for _, cv := range rssView {
if cv == nil {
continue
}
var needUpdate bool
needUpdate, err = repo.checkSourceNeedUpdate(ctx, cv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] checkSourceNeedUpdate error: %v", err)
err = nil
continue
}
// 保存
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %+v, need update(real): %v", cv.Source, needUpdate)
// 如果需要更新更新channel 和 content
if needUpdate {
err = repo.storage.UpsertSource(ctx, cv.Source)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert source error: %v", err)
}
}
var updateChannelView = &RssClientView{Source: cv.Source, Contents: []*RssContent{}}
err = repo.processContentsUpdate(ctx, cv, updateChannelView)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] processContentsUpdate error: %v", err)
continue
}
if len(updateChannelView.Contents) == 0 {
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %s, no new content", cv.Source.RssHubFeedPath)
continue
}
updateChannelView.Sort()
updated[updateChannelView.Source.ID] = updateChannelView
logrus.WithContext(ctx).Debugf("[rsshub syncRss] cv %s, new contents: %v", cv.Source.RssHubFeedPath, len(updateChannelView.Contents))
}
return
}
// checkSourceNeedUpdate 检查频道是否需要更新
func (repo *RssDomain) checkSourceNeedUpdate(ctx context.Context, source *RssSource) (needUpdate bool, err error) {
var sourceInDB *RssSource
sourceInDB, err = repo.storage.GetSourceByRssHubFeedLink(ctx, source.RssHubFeedPath)
if err != nil {
return
}
if sourceInDB == nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] source not found: %v", source.RssHubFeedPath)
return
}
source.ID = sourceInDB.ID
// 检查是否需要更新到db
if sourceInDB.IfNeedUpdate(source) {
needUpdate = true
}
return
}
// processContentsUpdate 处理内容(s)更新
func (repo *RssDomain) processContentsUpdate(ctx context.Context, cv *RssClientView, updateChannelView *RssClientView) error {
var err error
for _, content := range cv.Contents {
if content == nil {
continue
}
content.RssSourceID = cv.Source.ID
var existed bool
existed, err = repo.processContentItemUpdate(ctx, content)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert content error: %v", err)
err = nil
continue
}
if !existed {
updateChannelView.Contents = append(updateChannelView.Contents, content)
logrus.WithContext(ctx).Infof("[rsshub syncRss] cv %s, add new content: %v", cv.Source.RssHubFeedPath, content.Title)
}
}
return err
}
// processContentItemUpdate 处理单个内容更新
func (repo *RssDomain) processContentItemUpdate(ctx context.Context, content *RssContent) (existed bool, err error) {
existed, err = repo.storage.IsContentHashIDExist(ctx, content.HashID)
if err != nil {
return
}
// 不需要更新&不需要发送
if existed {
return
}
// 保存
err = repo.storage.UpsertContent(ctx, content)
if err != nil {
logrus.WithContext(ctx).Errorf("[rsshub syncRss] upsert content error: %v", err)
return
}
return
}