topic.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "go-common/app/interface/bbq/app-bbq/api/http/v1"
  6. topic "go-common/app/service/bbq/topic/api"
  7. "go-common/library/ecode"
  8. "go-common/library/log"
  9. "net/http"
  10. "net/url"
  11. )
  12. func (s *Service) getExtension(ctx context.Context, svids []int64) (res map[int64]*topic.VideoExtension, err error) {
  13. res = make(map[int64]*topic.VideoExtension, len(svids))
  14. // 0. check
  15. // 1. get extension
  16. req := &topic.ListExtensionReq{Svids: svids}
  17. reply, err := s.topicClient.ListExtension(ctx, req)
  18. if err != nil {
  19. log.Warnw(ctx, "log", "get extension fail")
  20. return
  21. }
  22. // 2. form extension
  23. for _, extension := range reply.List {
  24. res[extension.Svid] = extension
  25. }
  26. return
  27. }
  28. // TopicDetail 获取话题详情
  29. func (s *Service) TopicDetail(ctx context.Context, mid int64, req *topic.TopicVideosReq) (res *v1.TopicDetail, err error) {
  30. res = new(v1.TopicDetail)
  31. // 0. check
  32. if req.TopicId == 0 {
  33. err = ecode.TopicReqParamErr
  34. log.Warnw(ctx, "log", "topic id is 0")
  35. return
  36. }
  37. // 1. 获取话题信息及话题内视频
  38. topicDetails, err := s.topicClient.ListTopicVideos(ctx, req)
  39. if err != nil {
  40. log.Errorw(ctx, "log", "get list topic videos fail")
  41. return
  42. }
  43. // 2. 获取视频详情
  44. // 2.0 获取视频id
  45. var svids []int64
  46. topicVideoMap := make(map[int64]*topic.VideoItem)
  47. for _, item := range topicDetails.List {
  48. if _, exists := topicVideoMap[item.Svid]; !exists {
  49. topicVideoMap[item.Svid] = item
  50. svids = append(svids, item.Svid)
  51. }
  52. }
  53. // 2.1 获取详情
  54. svInfos, err := s.svInfos(ctx, svids, mid, false)
  55. if err != nil {
  56. log.Warnw(ctx, "log", "get sv infos fail", "svid", svids)
  57. return
  58. }
  59. // 3. 组装回包
  60. res.TopicInfo = topicDetails.TopicInfo
  61. res.HasMore = topicDetails.HasMore
  62. for _, item := range topicDetails.List {
  63. var topicVideo *v1.TopicVideo
  64. if svInfo, exists := svInfos[item.Svid]; !exists {
  65. log.Errorw(ctx, "log", "cannot find topicVideo response in topic detail", "svid", item.Svid)
  66. continue
  67. } else {
  68. topicVideo = new(v1.TopicVideo)
  69. topicVideo.VideoResponse = svInfo
  70. }
  71. topicVideo.CursorValue = item.CursorValue
  72. topicVideo.HotType = item.HotType
  73. res.List = append(res.List, topicVideo)
  74. }
  75. return
  76. }
  77. func (s *Service) getDiscoveryData(ctx context.Context, uri string) (data []byte, err error) {
  78. var ret struct {
  79. Code int `json:"code"`
  80. Msg string `json:"message"`
  81. Data json.RawMessage `json:"data"`
  82. }
  83. req, err := s.httpClient.NewRequest(http.MethodGet, uri, "", url.Values{})
  84. if err != nil {
  85. log.Errorw(ctx, "log", "http.NewRequest error", "err", err)
  86. return
  87. }
  88. if err = s.httpClient.Do(ctx, req, &ret); err != nil {
  89. log.Errorw(ctx, "log", "client Do error", "err", err)
  90. return
  91. }
  92. if ret.Code != 0 {
  93. log.Errorw(ctx, "log", "return code error", "code", ret.Code)
  94. return
  95. }
  96. data = ret.Data
  97. return
  98. }
  99. func (s *Service) getHotWords(ctx context.Context) (list []string, err error) {
  100. list = make([]string, 0, 1)
  101. data, err := s.getDiscoveryData(ctx, "http://bbq-mng.bilibili.co/bbq/cms/hotword/api")
  102. if err != nil {
  103. log.Warnw(ctx, "log", "get discovery data fail")
  104. return
  105. }
  106. var hotWordResponse struct {
  107. OnshelfList []string `json:"onshelf_list"`
  108. }
  109. err = json.Unmarshal(data, &hotWordResponse)
  110. if err != nil {
  111. log.Errorw(ctx, "log", "unmarshal hot word response fail", "data", string(data))
  112. return
  113. }
  114. list = hotWordResponse.OnshelfList
  115. if list == nil {
  116. list = make([]string, 0, 1)
  117. }
  118. return
  119. }
  120. func (s *Service) getBanner(ctx context.Context) (list []*v1.Banner, err error) {
  121. list = make([]*v1.Banner, 0, 1)
  122. data, err := s.getDiscoveryData(ctx, "http://bbq-mng.bilibili.co/bbq/cms/banner/api")
  123. if err != nil {
  124. log.Warnw(ctx, "log", "get discovery data fail")
  125. return
  126. }
  127. type httpBanner struct {
  128. Title string `json:"title"`
  129. ImgUrl string `json:"img_url"`
  130. JumpUrl string `json:"jump_url"`
  131. }
  132. var bannerResponse struct {
  133. BannerList []*httpBanner `json:"banner_list"`
  134. }
  135. bannerResponse.BannerList = make([]*httpBanner, 0)
  136. err = json.Unmarshal(data, &bannerResponse)
  137. if err != nil {
  138. log.Errorw(ctx, "log", "unmarshal hot word response fail", "data", string(data))
  139. return
  140. }
  141. for _, item := range bannerResponse.BannerList {
  142. banner := new(v1.Banner)
  143. banner.Name = item.Title
  144. banner.PIC = item.ImgUrl
  145. banner.Scheme = item.JumpUrl
  146. list = append(list, banner)
  147. }
  148. if list == nil {
  149. list = make([]*v1.Banner, 0, 1)
  150. }
  151. return
  152. }
  153. // Discovery 发现页
  154. func (s *Service) Discovery(ctx context.Context, mid int64, req *v1.DiscoveryReq) (res *v1.DiscoveryRes, err error) {
  155. res = new(v1.DiscoveryRes)
  156. res.BannerList = make([]*v1.Banner, 0, 10)
  157. res.HotWords = make([]string, 0, 10)
  158. res.TopicList = make([]*v1.TopicDetail, 0, 10)
  159. res.HasMore = false
  160. // check
  161. // 1. 条件判断
  162. if req.Page == 1 {
  163. // 请求热词
  164. if res.HotWords, err = s.getHotWords(ctx); err != nil {
  165. log.Warnw(ctx, "log", "get hot words fail", "err", err)
  166. }
  167. // 请求banner
  168. if res.BannerList, err = s.getBanner(ctx); err != nil {
  169. log.Warnw(ctx, "log", "get banner fail", "err", err)
  170. }
  171. }
  172. // 2. 请求话题详情
  173. reply, err := s.topicClient.ListDiscoveryTopics(ctx, &topic.ListDiscoveryTopicReq{Page: req.Page})
  174. if err != nil {
  175. log.Errorw(ctx, "log", "get discovery topics list fail")
  176. return
  177. }
  178. // 2.1 收集svid
  179. var svids []int64
  180. for _, topicDetail := range reply.List {
  181. for _, videoItem := range topicDetail.List {
  182. svids = append(svids, videoItem.Svid)
  183. }
  184. }
  185. // 2.2 获取视频详情
  186. svInfos, err := s.svInfos(ctx, svids, mid, false)
  187. if err != nil {
  188. log.Warnw(ctx, "log", "get sv infos fail", "svids", svids)
  189. return
  190. }
  191. // 3. 组装回包
  192. res.HasMore = reply.HasMore
  193. for _, topicDetail := range reply.List {
  194. newTopicDetail := new(v1.TopicDetail)
  195. newTopicDetail.TopicInfo = topicDetail.TopicInfo
  196. newTopicDetail.HasMore = topicDetail.HasMore
  197. for _, videoItem := range topicDetail.List {
  198. if val, exists := svInfos[videoItem.Svid]; exists {
  199. topicVideo := &v1.TopicVideo{CursorValue: videoItem.CursorValue, VideoResponse: val}
  200. newTopicDetail.List = append(newTopicDetail.List, topicVideo)
  201. } else {
  202. log.Warnw(ctx, "log", "get sv info fail", "svid", videoItem.Svid)
  203. }
  204. }
  205. if len(newTopicDetail.List) == 0 {
  206. log.Warnw(ctx, "log", "topic has nothing", "topic", topicDetail)
  207. continue
  208. }
  209. res.TopicList = append(res.TopicList, newTopicDetail)
  210. }
  211. return
  212. }
  213. // TopicSearch 话题搜索
  214. func (s *Service) TopicSearch(ctx context.Context, req *v1.TopicSearchReq) (res *v1.TopicSearchResponse, err error) {
  215. res = new(v1.TopicSearchResponse)
  216. if len(req.Keyword) == 0 {
  217. var reply *topic.ListTopicsReply
  218. reply, err = s.topicClient.ListTopics(ctx, &topic.ListTopicsReq{Page: 1})
  219. if err != nil {
  220. log.Warnw(ctx, "log", "get topic list fail", "err", err)
  221. return
  222. }
  223. res.List = reply.List
  224. res.HasMore = reply.HasMore
  225. }
  226. res.HasMore = false
  227. return
  228. }