You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
9.9 KiB
403 lines
9.9 KiB
package feed |
|
|
|
import ( |
|
"context" |
|
"strconv" |
|
"time" |
|
|
|
"go-common/app/interface/main/app-feed/model" |
|
"go-common/app/interface/main/app-feed/model/feed" |
|
"go-common/app/interface/main/app-feed/model/live" |
|
"go-common/app/interface/main/app-feed/model/tag" |
|
article "go-common/app/interface/openplatform/article/model" |
|
"go-common/app/service/main/archive/api" |
|
"go-common/app/service/main/archive/model/archive" |
|
busfeed "go-common/app/service/main/feed/model" |
|
"go-common/library/log" |
|
"go-common/library/sync/errgroup" |
|
) |
|
|
|
const ( |
|
_iosBanBangumi = 4310 |
|
_androidBanBangumi = 502000 |
|
_androidIBanBangumi = 104000 |
|
) |
|
|
|
func (s *Service) Upper(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) { |
|
if (plat == model.PlatIPhone && build > _iosBanBangumi) || (plat == model.PlatAndroid && build > _androidBanBangumi) || (plat == model.PlatAndroidI && build >= _androidIBanBangumi) || plat == model.PlatIPhoneB { |
|
is, lp = s.UpperFeed(c, mid, plat, build, pn, ps, now) |
|
} else { |
|
is, lp = s.UpperArchive(c, mid, plat, build, pn, ps, now) |
|
} |
|
return |
|
} |
|
|
|
// UpperFeed get the archives and bangumi for feed |
|
// if archives are less then `_minTotalCnt` then will fill with recommended archives |
|
func (s *Service) UpperFeed(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) { |
|
var ( |
|
err error |
|
hc bool |
|
uis, fis []*busfeed.Feed |
|
fp = pn == 1 |
|
) |
|
if fp { |
|
var ( |
|
unread int |
|
count = ps |
|
) |
|
if unread, err = s.upper.UnreadCountCache(c, mid); err != nil { |
|
log.Error("%+v", err) |
|
} else if unread != 0 { |
|
count = s.c.Feed.FeedCacheCount |
|
} |
|
if uis, err = s.upper.Feed(c, mid, pn, count); err != nil { |
|
log.Error("%+v", err) |
|
// get cache from redis |
|
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil { |
|
log.Error("%+v", err) |
|
} else if hc { |
|
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
} |
|
if len(uis) == 0 { |
|
is = _emptyItem |
|
lp = true |
|
return |
|
} |
|
} else if unread != 0 { |
|
s.addCache(func() { |
|
s.upper.AddUpItemCaches(context.Background(), mid, uis...) |
|
}) |
|
} |
|
} else { |
|
if uis, err = s.upper.Feed(c, mid, pn, ps); err != nil { |
|
log.Error("%+v", err) |
|
// get cache from redis |
|
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil { |
|
log.Error("%+v", err) |
|
} else if hc { |
|
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
} |
|
if len(uis) == 0 { |
|
is = _emptyItem |
|
lp = true |
|
return |
|
} |
|
} |
|
} |
|
// handle feed |
|
if len(uis) > ps { |
|
fis = uis[:ps] |
|
} else { |
|
fis = uis |
|
} |
|
is = s.upperItem(c, fis, mid, now) |
|
if len(is) < ps { |
|
lp = true |
|
} |
|
if len(is) == 0 { |
|
is = _emptyItem |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) upperCache(c context.Context, mid int64, plat int8, build, pn, ps int, now time.Time) (uis []*busfeed.Feed, err error) { |
|
var ( |
|
start = (pn - 1) * ps |
|
end = start + ps // from slice, end no -1 |
|
aids []int64 |
|
am map[int64]*api.Arc |
|
seasonIDs []int64 |
|
psm map[int64]*busfeed.Bangumi |
|
) |
|
if uis, aids, seasonIDs, err = s.upper.UpItemCaches(c, mid, start, end); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
if len(aids) > 0 { |
|
if am, err = s.arc.Archives(c, aids); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
} |
|
if len(seasonIDs) > 0 && ((plat == model.PlatIPhone && build > _iosBanBangumi) || (plat == model.PlatAndroid && build > _androidBanBangumi) || plat == model.PlatIPhoneB) { |
|
if psm, err = s.bgm.PullSeasons(c, seasonIDs, now); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
} |
|
for _, ui := range uis { |
|
switch ui.Type { |
|
case busfeed.ArchiveType: |
|
if a, ok := am[ui.ID]; ok { |
|
ui.Archive = a |
|
} |
|
for _, r := range ui.Fold { |
|
if a, ok := am[r.Aid]; ok { |
|
r = a |
|
} else { |
|
r = nil |
|
} |
|
} |
|
case busfeed.BangumiType: |
|
if s, ok := psm[ui.ID]; ok { |
|
ui.Bangumi = s |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) UpperArchive(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) { |
|
var ( |
|
err error |
|
uis []*busfeed.Feed |
|
hc bool |
|
) |
|
if uis, err = s.upper.ArchiveFeed(c, mid, pn, ps); err != nil { |
|
log.Error("%+v", err) |
|
// get cache from redis |
|
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil { |
|
log.Error("%+v", err) |
|
} else if hc { |
|
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
} |
|
if len(uis) == 0 { |
|
is = _emptyItem |
|
lp = true |
|
return |
|
} |
|
} |
|
// handle feed |
|
is = s.upperItem(c, uis, mid, now) |
|
if len(is) < ps { |
|
lp = true |
|
} |
|
if len(is) == 0 { |
|
is = _emptyItem |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) UpperBangumi(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) { |
|
var ( |
|
err error |
|
uis []*busfeed.Feed |
|
hc bool |
|
) |
|
if uis, err = s.upper.BangumiFeed(c, mid, pn, ps); err != nil { |
|
log.Error("%+v", err) |
|
// get cache from redis |
|
if hc, err = s.upper.ExpireUpItem(c, mid); err != nil { |
|
log.Error("%+v", err) |
|
} else if hc { |
|
if uis, err = s.upperCache(c, mid, plat, build, pn, ps, now); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
} |
|
if len(uis) == 0 { |
|
is = _emptyItem |
|
lp = true |
|
return |
|
} |
|
} |
|
// handle feed |
|
is = s.upperItem(c, uis, mid, now) |
|
if len(is) < ps { |
|
lp = true |
|
} |
|
if len(is) == 0 { |
|
is = _emptyItem |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) UpperRecent(c context.Context, mid, upperID, aid int64, now time.Time) (is []*feed.Item) { |
|
var ( |
|
err error |
|
uis []*busfeed.Feed |
|
) |
|
if uis, err = s.upper.Recent(c, upperID, aid); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
// handle feed |
|
is = s.upperItem(c, uis, mid, now) |
|
if len(is) == 0 { |
|
is = _emptyItem |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) upperItem(c context.Context, uis []*busfeed.Feed, mid int64, now time.Time) (is []*feed.Item) { |
|
var ( |
|
g *errgroup.Group |
|
ctx context.Context |
|
owners, aids []int64 |
|
follows map[int64]bool |
|
tm map[string][]*tag.Tag |
|
err error |
|
) |
|
owners = make([]int64, 0, len(uis)) |
|
for _, ui := range uis { |
|
if ui != nil { |
|
if ui.Archive != nil { |
|
owners = append(owners, ui.Archive.Author.Mid) |
|
aids = append(aids, ui.Archive.Aid) |
|
} |
|
for _, r := range ui.Fold { |
|
if r != nil { |
|
aids = append(aids, r.Aid) |
|
} |
|
} |
|
} |
|
} |
|
g, ctx = errgroup.WithContext(c) |
|
if len(owners) != 0 { |
|
g.Go(func() (err error) { |
|
follows = s.acc.Relations3(ctx, owners, mid) |
|
return |
|
}) |
|
} |
|
if len(aids) != 0 { |
|
g.Go(func() (err error) { |
|
if tm, err = s.tg.Tags(ctx, mid, aids, now); err != nil { |
|
log.Error("%+v", err) |
|
err = nil |
|
} |
|
return |
|
}) |
|
} |
|
if err = g.Wait(); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
is = make([]*feed.Item, 0, len(uis)) |
|
for _, ui := range uis { |
|
if ui != nil { |
|
switch ui.Type { |
|
case busfeed.ArchiveType: |
|
if ui.Archive != nil && ui.Archive.IsNormal() { |
|
i := &feed.Item{} |
|
i.FromAv(&archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(ui.Archive)}) |
|
i.RecCnt = len(ui.Fold) |
|
if len(ui.Fold) > 0 { |
|
ris := make([]*feed.Item, 0, len(ui.Fold)) |
|
for _, r := range ui.Fold { |
|
if r != nil && r.IsNormal() { |
|
ri := &feed.Item{} |
|
ri.FromAv(&archive.ArchiveWithPlayer{Archive3: archive.BuildArchive3(r)}) |
|
if infos, ok := tm[strconv.FormatInt(r.Aid, 10)]; ok { |
|
if len(infos) != 0 { |
|
ri.Tag = &feed.Tag{TagID: infos[0].ID, TagName: infos[0].Name, IsAtten: infos[0].IsAtten, Count: &feed.TagCount{Atten: infos[0].Count.Atten}} |
|
} |
|
} |
|
if follows[i.Mid] { |
|
ri.IsAtten = 1 |
|
} |
|
ris = append(ris, ri) |
|
} |
|
} |
|
i.Recent = ris |
|
} |
|
if infos, ok := tm[strconv.FormatInt(ui.Archive.Aid, 10)]; ok { |
|
if len(infos) != 0 { |
|
i.Tag = &feed.Tag{TagID: infos[0].ID, TagName: infos[0].Name, IsAtten: infos[0].IsAtten, Count: &feed.TagCount{Atten: infos[0].Count.Atten}} |
|
} |
|
} |
|
if follows[i.Mid] { |
|
i.IsAtten = 1 |
|
} |
|
is = append(is, i) |
|
} |
|
case busfeed.BangumiType: |
|
if ui.Bangumi != nil { |
|
i := &feed.Item{} |
|
i.FromUpBangumi(ui.Bangumi) |
|
is = append(is, i) |
|
} |
|
} |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) UpperLive(c context.Context, mid int64) (is []*feed.Item, count int) { |
|
var ( |
|
err error |
|
fs []*live.Feed |
|
pn = 1 |
|
ps = s.c.Feed.LiveFeedCount |
|
) |
|
if fs, count, err = s.lv.FeedList(c, mid, pn, ps); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
for _, f := range fs { |
|
i := &feed.Item{} |
|
i.FromUpLive(f) |
|
is = append(is, i) |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) UpperArticle(c context.Context, mid int64, plat int8, build int, pn, ps int, now time.Time) (is []*feed.Item, lp bool) { |
|
var ( |
|
err error |
|
uis []*article.Meta |
|
) |
|
if uis, err = s.upper.ArticleFeed(c, mid, pn, ps); err != nil { |
|
log.Error("%+v", err) |
|
return |
|
} |
|
// handle feed |
|
is = s.articleItem(c, uis, mid) |
|
if len(is) < ps { |
|
lp = true |
|
} |
|
if len(is) == 0 { |
|
is = _emptyItem |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) articleItem(c context.Context, uis []*article.Meta, mid int64) (is []*feed.Item) { |
|
is = make([]*feed.Item, 0, len(uis)) |
|
for _, ui := range uis { |
|
if ui != nil { |
|
i := &feed.Item{} |
|
i.FromUpArticle(ui) |
|
is = append(is, i) |
|
} |
|
} |
|
return |
|
} |
|
|
|
func (s *Service) UnreadCount(c context.Context, mid int64, plat int8, build int, now time.Time) (total, feedCount, articleCount int) { |
|
var ( |
|
withoutBangumi = true |
|
err error |
|
) |
|
if (plat == model.PlatIPhone && build > _iosBanBangumi) || (plat == model.PlatAndroid && build > _androidBanBangumi) || plat == model.PlatIPhoneB { |
|
withoutBangumi = false |
|
} |
|
if feedCount, err = s.upper.AppUnreadCount(c, mid, withoutBangumi); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
if true { |
|
if articleCount, err = s.upper.ArticleUnreadCount(c, mid); err != nil { |
|
log.Error("%+v", err) |
|
} |
|
} |
|
total = feedCount + articleCount |
|
// add feed unread count cache |
|
if feedCount > 0 { |
|
s.addCache(func() { |
|
s.upper.AddUnreadCountCache(context.Background(), mid, feedCount) |
|
}) |
|
} |
|
return |
|
}
|
|
|