feed.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. package feed
  2. import (
  3. "encoding/json"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "go-common/app/interface/main/app-card/model/card/audio"
  8. "go-common/app/interface/main/app-card/model/card/bangumi"
  9. cardlive "go-common/app/interface/main/app-card/model/card/live"
  10. "go-common/app/interface/main/app-card/model/card/operate"
  11. shopping "go-common/app/interface/main/app-card/model/card/show"
  12. "go-common/app/interface/main/app-channel/model"
  13. "go-common/app/interface/main/app-channel/model/activity"
  14. "go-common/app/interface/main/app-channel/model/card"
  15. "go-common/app/interface/main/app-channel/model/channel"
  16. "go-common/app/interface/main/app-channel/model/dislike"
  17. "go-common/app/interface/main/app-channel/model/recommend"
  18. bustag "go-common/app/interface/main/tag/model"
  19. tag "go-common/app/interface/main/tag/model"
  20. article "go-common/app/interface/openplatform/article/model"
  21. account "go-common/app/service/main/account/model"
  22. "go-common/app/service/main/archive/model/archive"
  23. relation "go-common/app/service/main/relation/model"
  24. episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1"
  25. xtime "go-common/library/time"
  26. )
  27. const (
  28. _seasonNoSeason = 1
  29. _seasonUpper = 4
  30. _activityForm = "2006-01-02 15:04:05"
  31. _convergeMinCount = 2
  32. )
  33. type Show struct {
  34. Topic *Item `json:"topic,omitempty"`
  35. Feed []*Item `json:"feed"`
  36. }
  37. // Item is feed item,
  38. type Item struct {
  39. Title string `json:"title,omitempty"`
  40. Subtitle string `json:"subtitle,omitempty"`
  41. Cover string `json:"cover,omitempty"`
  42. URI string `json:"uri,omitempty"`
  43. Redirect string `json:"redirect,omitempty"`
  44. RedirectURI string `json:"redirect_uri,omitempty"`
  45. Param string `json:"param,omitempty"`
  46. Goto string `json:"goto,omitempty"`
  47. ViewType string `json:"view_type,omitempty"`
  48. Kind string `json:"kind,omitempty"`
  49. Desc string `json:"desc,omitempty"`
  50. Play int `json:"play,omitempty"`
  51. Danmaku int `json:"danmaku,omitempty"`
  52. Reply int `json:"reply,omitempty"`
  53. Fav int `json:"favorite,omitempty"`
  54. Coin int `json:"coin,omitempty"`
  55. Share int `json:"share,omitempty"`
  56. Like int `json:"like,omitempty"`
  57. Count int `json:"count,omitempty"`
  58. Status int8 `json:"status,omitempty"`
  59. Type int8 `json:"type,omitempty"`
  60. Badge string `json:"badge,omitempty"`
  61. StatType int8 `json:"stat_type,omitempty"`
  62. RcmdReason *RcmdReason `json:"rcmd_reason,omitempty"`
  63. Item []*Item `json:"item,omitempty"`
  64. // sortedset index
  65. Idx int64 `json:"idx,omitempty"`
  66. // av info
  67. Cid int64 `json:"cid,omitempty"`
  68. Rid int32 `json:"tid,omitempty"`
  69. TName string `json:"tname,omitempty"`
  70. Tag *Tag `json:"tag,omitempty"`
  71. DisklikeReasons []*dislike.DisklikeReason `json:"dislike_reasons,omitempty"`
  72. PTime xtime.Time `json:"ctime,omitempty"`
  73. Autoplay int32 `json:"autoplay,omitempty"`
  74. // av stat
  75. Duration int64 `json:"duration,omitempty"`
  76. // upper
  77. Mid int64 `json:"mid,omitempty"`
  78. Name string `json:"name,omitempty"`
  79. Face string `json:"face,omitempty"`
  80. IsAtten int8 `json:"is_atten,omitempty"`
  81. Fans int64 `json:"fans,omitempty"`
  82. RecCnt int `json:"recent_count,omitempty"`
  83. Recent []*Item `json:"recent,omitempty"`
  84. Official *OfficialInfo `json:"official,omitempty"`
  85. // live
  86. Online int `json:"online,omitempty"`
  87. Area string `json:"area,omitempty"`
  88. AreaID int `json:"area_id,omitempty"`
  89. Area2 *Area2 `json:"area2,omitempty"`
  90. // bangumi
  91. Index string `json:"index,omitempty"`
  92. IndexTitle string `json:"index_title,omitempty"`
  93. CoverMark string `json:"cover_mark,omitempty"`
  94. Finish bool `json:"finish,omitempty"`
  95. LatestIndex string `json:"last_index,omitempty"`
  96. // bangumi recommend
  97. Updates int `json:"updates,omitempty"`
  98. // live or bangumi
  99. From int8 `json:"from,omitempty"`
  100. // adviertisement
  101. RequestID string `json:"request_id,omitempty"`
  102. CreativeID int64 `json:"creative_id,omitempty"`
  103. SrcID int `json:"src_id,omitempty"`
  104. IsAd bool `json:"is_ad,omitempty"`
  105. IsAdLoc bool `json:"is_ad_loc,omitempty"`
  106. AdCb string `json:"ad_cb,omitempty"`
  107. ShowURL string `json:"show_url,omitempty"`
  108. ClickURL string `json:"click_url,omitempty"`
  109. ClientIP string `json:"client_ip,omitempty"`
  110. CmMark int64 `json:"cm_mark,omitempty"`
  111. AdIndex int `json:"ad_index,omitempty"`
  112. Extra json.RawMessage `json:"extra,omitempty"`
  113. CardIndex int `json:"card_index,omitempty"`
  114. // activity
  115. STime string `json:"stime,omitempty"`
  116. ETime string `json:"etime,omitempty"`
  117. // tag
  118. Tags []*channel.Tag `json:"tags,omitempty"`
  119. // rank
  120. Cover1 string `json:"cover1,omitempty"`
  121. Cover2 string `json:"cover2,omitempty"`
  122. Cover3 string `json:"cover3,omitempty"`
  123. // banner`
  124. Hash string `json:"hash,omitempty"`
  125. // upper article
  126. Covers []string `json:"covers,omitempty"`
  127. Temple int `json:"temple,omitempty"`
  128. Template int `json:"template,omitempty"`
  129. Category *Category `json:"category,omitempty"`
  130. BannerURL string `json:"banner_url,omitempty"`
  131. // game download
  132. Button *Button `json:"button,omitempty"`
  133. Download int32 `json:"download,omitempty"`
  134. BigCover string `json:"big_cover,omitempty"`
  135. // special
  136. HideBadge bool `json:"hide_badge,omitempty"`
  137. Ratio float64 `json:"ratio,omitempty"`
  138. // shopping
  139. City string `json:"city,omitempty"`
  140. PType string `json:"ptype,omitempty"`
  141. Price string `json:"price,omitempty"`
  142. Square string `json:"square,omitempty"`
  143. // news
  144. Content string `json:"content,omitempty"`
  145. // bigdata source
  146. Source string `json:"-"`
  147. AvFeature json.RawMessage `json:"-"`
  148. // common
  149. GotoOrg string `json:"-"`
  150. FromType string `json:"from_type,omitempty"`
  151. Pos int `json:"-"`
  152. // audio
  153. SongTitle string `json:"song_title,omitempty"`
  154. }
  155. type Tag struct {
  156. TagID int64 `json:"tag_id,omitempty"`
  157. TagName string `json:"tag_name,omitempty"`
  158. IsAtten int8 `json:"is_atten,omitempty"`
  159. Count *TagCount `json:"count,omitempty"`
  160. Name string `json:"name,omitempty"`
  161. URI string `json:"uri,omitempty"`
  162. //channel
  163. ID int64 `json:"id,omitempty"`
  164. Face string `json:"face,omitempty"`
  165. Fans int `json:"fans,omitempty"`
  166. }
  167. type RcmdReason struct {
  168. ID int `json:"id,omitempty"`
  169. Content string `json:"content,omitempty"`
  170. BgColor string `json:"bg_color,omitempty"`
  171. IconLocation string `json:"icon_location,omitempty"`
  172. Message string `json:"message,omitempty"`
  173. }
  174. type TagCount struct {
  175. Atten int `json:"atten,omitempty"`
  176. }
  177. type Category struct {
  178. ID int64 `json:"id,omitempty"`
  179. Name string `json:"name,omitempty"`
  180. Children *Category `json:"children,omitempty"`
  181. }
  182. type Button struct {
  183. Name string `json:"name,omitempty"`
  184. URI string `json:"uri,omitempty"`
  185. RedirectURI string `json:"redirect_uri,omitempty"`
  186. }
  187. type Area2 struct {
  188. ID int64 `json:"id,omitempty"`
  189. Name string `json:"name,omitempty"`
  190. Children *Area2 `json:"children,omitempty"`
  191. }
  192. type OfficialInfo struct {
  193. Role int8 `json:"role,omitempty"`
  194. Title string `json:"title,omitempty"`
  195. Desc string `json:"desc,omitempty"`
  196. }
  197. func (i *Item) fillArcStat(a *archive.Archive3) {
  198. if a.Access == 0 {
  199. i.Play = int(a.Stat.View)
  200. }
  201. i.Danmaku = int(a.Stat.Danmaku)
  202. i.Reply = int(a.Stat.Reply)
  203. i.Fav = int(a.Stat.Fav)
  204. i.Coin = int(a.Stat.Coin)
  205. i.Share = int(a.Stat.Share)
  206. i.Like = int(a.Stat.Like)
  207. }
  208. func (i *Item) FromPlayerAv(a *archive.ArchiveWithPlayer) {
  209. if i.Title == "" {
  210. i.Title = a.Title
  211. }
  212. if i.Cover == "" {
  213. i.Cover = model.CoverURLHTTPS(a.Pic)
  214. } else {
  215. i.Cover = model.CoverURLHTTPS(i.Cover)
  216. }
  217. i.Param = strconv.FormatInt(a.Aid, 10)
  218. i.Goto = model.GotoAv
  219. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  220. i.Cid = a.FirstCid
  221. i.Rid = a.TypeID
  222. i.TName = a.TypeName
  223. i.Desc = strconv.Itoa(int(a.Stat.Danmaku)) + "弹幕"
  224. i.fillArcStat(a.Archive3)
  225. i.Duration = a.Duration
  226. i.Mid = a.Author.Mid
  227. i.Name = a.Author.Name
  228. i.Face = a.Author.Face
  229. i.PTime = a.PubDate
  230. i.Cid = a.FirstCid
  231. i.Autoplay = a.Rights.Autoplay
  232. }
  233. func (i *Item) FromDislikeReason() {
  234. i.DisklikeReasons = []*dislike.DisklikeReason{
  235. &dislike.DisklikeReason{ReasonID: _seasonUpper, ReasonName: "UP主:" + i.Name},
  236. &dislike.DisklikeReason{ReasonID: _seasonNoSeason, ReasonName: "不感兴趣"},
  237. }
  238. }
  239. func (i *Item) FromRcmdReason(c *card.Card) {
  240. var content string
  241. switch c.ReasonType {
  242. case 0:
  243. content = ""
  244. case 1:
  245. content = "编辑精选"
  246. case 2:
  247. content = "热门推荐"
  248. case 3:
  249. content = c.Reason
  250. }
  251. if content != "" {
  252. i.RcmdReason = &RcmdReason{ID: 1, Content: content, BgColor: "yellow", IconLocation: "left_top"}
  253. }
  254. }
  255. func (i *Item) FromLive(r *cardlive.Room) {
  256. if r.LiveStatus != 1 || r.Title == "" || r.Cover == "" {
  257. return
  258. }
  259. i.Title = r.Title
  260. i.Cover = r.Cover
  261. i.Goto = model.GotoLive
  262. i.Param = strconv.FormatInt(r.RoomID, 10)
  263. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, 0, model.LiveRoomHandler(r))
  264. i.Name = r.Uname
  265. i.Mid = r.UID
  266. i.Face = r.Face
  267. i.Online = int(r.Online)
  268. i.Autoplay = 1
  269. // i.Area = r.Area
  270. // i.AreaID = r.AreaID
  271. i.Area2 = &Area2{ID: r.AreaV2ParentID, Name: r.AreaV2ParentName, Children: &Area2{ID: r.AreaV2ID, Name: r.AreaV2Name}}
  272. i.Autoplay = 1
  273. }
  274. func (i *Item) FromSeason(b *bangumi.Season) {
  275. if i.Title == "" {
  276. i.Title = b.Title
  277. }
  278. if i.Cover == "" {
  279. i.Cover = b.Cover
  280. }
  281. i.Goto = model.GotoUpBangumi
  282. i.Param = strconv.FormatInt(b.SeasonID, 10)
  283. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, 0, nil)
  284. i.Play = int(b.PlayCount)
  285. i.Fav = int(b.Favorites)
  286. i.Type = b.SeasonType
  287. i.Badge = b.TypeBadge
  288. i.Desc = b.UpdateDesc
  289. i.Face = b.SeasonCover
  290. i.Square = b.SeasonCover
  291. }
  292. func (i *Item) FromPGCSeason(s *episodegrpc.EpisodeCardsProto) {
  293. if i.Title == "" {
  294. i.Title = s.Season.Title
  295. }
  296. if i.Cover == "" {
  297. i.Cover = s.Cover
  298. }
  299. i.Goto = model.GotoBangumi
  300. i.Param = strconv.Itoa(int(s.EpisodeId))
  301. i.URI = model.FillURI(model.GotoBangumi, i.Param, 0, 0, 0, nil)
  302. i.Index = s.Title
  303. i.IndexTitle = s.LongTitle
  304. i.Status = int8(s.Season.SeasonStatus)
  305. i.CoverMark = s.Season.Badge
  306. i.Play = int(s.Season.Stat.View)
  307. i.Fav = int(s.Season.Stat.Follow)
  308. i.Type = int8(s.Season.SeasonType)
  309. i.Badge = s.Season.SeasonTypeName
  310. if s.Season.IsFinish == 1 {
  311. i.Finish = true
  312. }
  313. i.Count = int(s.Season.TotalCount)
  314. i.LatestIndex = s.Title
  315. i.Desc = s.Season.NewEpShow
  316. i.Face = s.Season.Cover
  317. i.Square = s.Season.Cover
  318. }
  319. func (i *Item) FromActivity(a *activity.Activity, now time.Time) {
  320. stime, err := time.ParseInLocation(_activityForm, a.STime, time.Local)
  321. if err != nil {
  322. return
  323. }
  324. etime, err := time.ParseInLocation(_activityForm, a.ETime, time.Local)
  325. if err != nil {
  326. return
  327. }
  328. if now.After(etime) {
  329. i.Status = 1
  330. } else if now.Before(stime) {
  331. i.Status = 2
  332. }
  333. i.Title = a.Name
  334. i.Cover = a.H5Cover
  335. i.Goto = model.GotoActivity
  336. i.URI = model.FillURI(i.Goto, a.H5URL, 0, 0, 0, nil)
  337. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, 0)
  338. i.Desc = a.Desc
  339. i.STime = a.STime
  340. i.ETime = a.ETime
  341. i.Param = strconv.FormatInt(a.ID, 10)
  342. }
  343. func (i *Item) FromTopic(a *activity.Activity) {
  344. i.Title = a.Name
  345. i.Cover = a.H5Cover
  346. i.Goto = model.GotoTopic
  347. i.URI = model.FillURI(i.Goto, a.H5URL, 0, 0, 0, nil)
  348. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, 0)
  349. i.Desc = a.Desc
  350. i.Param = strconv.FormatInt(a.ID, 10)
  351. }
  352. func (i *Item) FromSpecial(id int64, title, cover, desc, url string, typ int, badge string, size string) {
  353. if title == "" || cover == "" {
  354. return
  355. }
  356. i.Title = title
  357. i.Cover = cover
  358. i.Goto = model.GotoSpecial
  359. i.URI = model.FillURI(i.Goto, url, typ, 0, 0, nil)
  360. i.Redirect = model.FillRedirect(i.Goto, typ)
  361. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, typ)
  362. i.Desc = desc
  363. i.Param = strconv.FormatInt(id, 10)
  364. i.HideBadge = true
  365. i.Badge = badge
  366. var ratio float64
  367. if size == "1020x300" {
  368. ratio = 34
  369. } else if size == "1020x378" {
  370. ratio = 27
  371. }
  372. i.Ratio = ratio
  373. }
  374. func (i *Item) FromTopstick(id int64, title, cover, desc, url string, typ int) {
  375. if title == "" {
  376. return
  377. }
  378. i.Title = title
  379. i.Goto = model.GotoTopstick
  380. i.URI = model.FillURI(i.Goto, url, typ, 0, 0, nil)
  381. i.Redirect = model.FillRedirect(i.Goto, typ)
  382. if desc == "" {
  383. i.Desc = "立即查看"
  384. } else {
  385. i.Desc = desc
  386. }
  387. i.Param = strconv.FormatInt(id, 10)
  388. }
  389. func (i *Item) FromSpecialS(id int64, title, cover, desc, url string, typ int, badge string) {
  390. if title == "" || cover == "" {
  391. return
  392. }
  393. i.Title = title
  394. i.Cover = cover
  395. i.Goto = model.GotoSpecialS
  396. i.URI = model.FillURI(i.Goto, url, typ, 0, 0, nil)
  397. i.Redirect = model.FillRedirect(i.Goto, typ)
  398. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, typ)
  399. i.Desc = desc
  400. i.Param = strconv.FormatInt(id, 10)
  401. i.HideBadge = true
  402. i.Badge = badge
  403. }
  404. func (i *Item) FromConverge(c *operate.Converge, am map[int64]*archive.ArchiveWithPlayer, rm map[int64]*cardlive.Room, artm map[int64]*article.Meta) {
  405. if len(c.Items) < _convergeMinCount {
  406. return
  407. }
  408. cis := []*Item{}
  409. for _, content := range c.Items {
  410. ci := &Item{Title: content.Title}
  411. switch content.Goto {
  412. case model.GotoAv:
  413. if a, ok := am[content.Pid]; ok && a.IsNormal() {
  414. if ci.Title == "" {
  415. ci.Title = a.Title
  416. }
  417. ci.Cover = a.Pic
  418. ci.Goto = model.GotoAv
  419. ci.Param = strconv.FormatInt(a.Aid, 10)
  420. ci.URI = model.FillURI(ci.Goto, ci.Param, 0, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  421. ci.fillArcStat(a.Archive3)
  422. ci.Duration = a.Duration
  423. cis = append(cis, ci)
  424. }
  425. case model.GotoLive:
  426. if r, ok := rm[content.ID]; ok {
  427. if r.LiveStatus == 0 || r.Title == "" || r.Cover == "" {
  428. continue
  429. }
  430. if ci.Title == "" {
  431. ci.Title = r.Title
  432. }
  433. ci.Cover = r.Cover
  434. ci.Goto = model.GotoLive
  435. ci.Param = strconv.FormatInt(r.RoomID, 10)
  436. ci.Online = int(r.Online)
  437. ci.URI = model.FillURI(ci.Goto, ci.Param, 0, 0, 0, model.LiveRoomHandler(r))
  438. // ci.RedirectURI = model.FillRedirectURI(ci.Goto, ci.URI, 0)
  439. ci.Badge = "直播"
  440. cis = append(cis, ci)
  441. }
  442. case model.GotoArticle:
  443. if art, ok := artm[content.ID]; ok {
  444. ci.Title = art.Title
  445. ci.Desc = art.Summary
  446. if len(art.ImageURLs) != 0 {
  447. ci.Cover = art.ImageURLs[0]
  448. }
  449. ci.Goto = model.GotoArticle
  450. ci.Param = strconv.FormatInt(art.ID, 10)
  451. ci.URI = model.FillURI(ci.Goto, ci.Param, 0, 0, 0, nil)
  452. if art.Stats != nil {
  453. ci.fillArtStat(art)
  454. }
  455. ci.Badge = "文章"
  456. cis = append(cis, ci)
  457. }
  458. }
  459. }
  460. if len(cis) < _convergeMinCount {
  461. return
  462. }
  463. i.Item = cis
  464. i.Goto = model.GotoConverge
  465. i.URI = model.FillURI(i.Goto, c.ReValue, c.ReType, 0, 0, nil)
  466. i.Redirect = model.FillRedirect(i.Goto, c.ReType)
  467. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, c.ReType)
  468. i.Title = c.Title
  469. i.Cover = c.Cover
  470. i.Param = strconv.FormatInt(c.ID, 10)
  471. }
  472. func (i *Item) fillArtStat(m *article.Meta) {
  473. i.Play = int(m.Stats.View)
  474. i.Reply = int(m.Stats.Reply)
  475. }
  476. func (i *Item) FromGameDownloadS(d *operate.Download, plat int8, build int) {
  477. i.Title = d.Title
  478. i.Cover = d.DoubleCover
  479. i.BigCover = d.Cover
  480. i.Goto = model.GotoGameDownloadS
  481. i.ViewType = "bili_game_download_layout"
  482. i.Desc = d.Desc
  483. i.URI = model.FillURI(i.Goto, d.URLValue, d.URLType, plat, build, nil)
  484. i.Redirect = model.FillRedirect(i.Goto, d.URLType)
  485. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, d.URLType)
  486. i.Face = d.Icon
  487. i.Button = &Button{Name: d.ButtonText, URI: model.FillURI(i.Goto, d.ReValue, d.ReType, plat, build, nil)}
  488. i.Param = strconv.FormatInt(d.ID, 10)
  489. i.Download = d.Number
  490. }
  491. func (i *Item) FromGameDownload(d *operate.Download, plat int8, build int) {
  492. if d.URLValue == "" || d.ReValue == "" {
  493. return
  494. }
  495. i.Title = d.Title
  496. i.Cover = d.Cover
  497. i.Goto = model.GotoGameDownload
  498. i.ViewType = "bili_game_download_layout"
  499. i.Desc = d.Desc
  500. i.URI = model.FillURI(i.Goto, d.URLValue, d.URLType, plat, build, nil)
  501. i.Redirect = model.FillRedirect(i.Goto, d.URLType)
  502. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, d.URLType)
  503. i.Face = d.Icon
  504. i.Button = &Button{Name: d.ButtonText, URI: model.FillURI(i.Goto, d.ReValue, d.ReType, plat, build, nil)}
  505. i.Param = strconv.FormatInt(d.ID, 10)
  506. i.Download = d.Number
  507. }
  508. func (i *Item) FromArticle(m *article.Meta) {
  509. if m.State < 0 || (m.TemplateID != 3 && m.TemplateID != 4) {
  510. return
  511. }
  512. i.Title = m.Title
  513. i.Desc = m.Summary
  514. i.Covers = m.ImageURLs
  515. i.Goto = model.GotoArticle
  516. i.Param = strconv.FormatInt(m.ID, 10)
  517. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, 0, nil)
  518. if m.Author != nil {
  519. i.Mid = m.Author.Mid
  520. i.Name = m.Author.Name
  521. i.Face = m.Author.Face
  522. }
  523. if len(m.Categories) >= 2 && m.Categories[0] != nil && m.Categories[1] != nil {
  524. i.Category = &Category{ID: m.Categories[0].ID, Name: m.Categories[0].Name}
  525. i.Category.Children = &Category{ID: m.Categories[1].ID, Name: m.Categories[1].Name}
  526. }
  527. if m.Stats != nil {
  528. i.fillArtStat(m)
  529. }
  530. // i.Temple = int(m.TemplateID)
  531. // if i.Temple == 4 {
  532. // i.Temple = 1
  533. // }
  534. i.Template = int(m.TemplateID)
  535. i.BannerURL = m.BannerURL
  536. i.PTime = m.PublishTime
  537. }
  538. func (i *Item) FromArticleS(m *article.Meta) {
  539. if m.State < 0 {
  540. return
  541. }
  542. i.Title = m.Title
  543. i.Desc = m.Summary
  544. i.Covers = m.ImageURLs
  545. i.Goto = model.GotoArticleS
  546. i.Param = strconv.FormatInt(m.ID, 10)
  547. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, 0, nil)
  548. if m.Author != nil {
  549. i.Mid = m.Author.Mid
  550. i.Name = m.Author.Name
  551. i.Face = m.Author.Face
  552. }
  553. if len(m.Categories) >= 2 && m.Categories[0] != nil && m.Categories[1] != nil {
  554. i.Category = &Category{ID: m.Categories[0].ID, Name: m.Categories[0].Name}
  555. i.Category.Children = &Category{ID: m.Categories[1].ID, Name: m.Categories[1].Name}
  556. }
  557. if m.Stats != nil {
  558. i.fillArtStat(m)
  559. }
  560. // i.Temple = int(m.TemplateID)
  561. i.Template = int(m.TemplateID)
  562. i.BannerURL = m.BannerURL
  563. i.PTime = m.PublishTime
  564. }
  565. func (i *Item) FromShoppingS(c *shopping.Shopping) {
  566. if c.Name == "" || c.PerformanceImage == "" || c.URL == "" {
  567. return
  568. }
  569. i.Title = c.Name
  570. if strings.HasPrefix(c.PerformanceImage, "http:") || strings.HasPrefix(c.PerformanceImage, "https:") {
  571. i.Cover = c.PerformanceImage
  572. } else {
  573. i.Cover = "http:" + c.PerformanceImage
  574. }
  575. i.Goto = model.GotoShoppingS
  576. i.URI = model.FillURI(i.Goto, c.URL, 0, 0, 0, nil)
  577. // i.RedirectURI = model.FillRedirectURI(i.Goto, i.URI, 0)
  578. i.STime = c.STime
  579. i.ETime = c.ETime
  580. i.City = c.CityName
  581. if len(c.Tags) != 0 {
  582. i.PType = c.Tags[0].TagName
  583. }
  584. i.Param = strconv.FormatInt(c.ID, 10)
  585. // 竖图
  586. i.Subtitle = c.Subname
  587. i.Price = c.Pricelt
  588. i.Desc = c.Want
  589. i.Type = c.Type
  590. }
  591. func (i *Item) FromAudio(a *audio.Audio) {
  592. i.Title = a.Title
  593. i.Cover = a.CoverURL
  594. i.Param = strconv.FormatInt(a.MenuID, 10)
  595. i.Goto = model.GotoAudio
  596. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, 0, nil) + "?from=tianma"
  597. i.Play = int(a.PlayNum)
  598. i.Count = a.RecordNum
  599. i.Fav = int(a.FavoriteNum)
  600. i.Face = a.Face
  601. titles := make([]string, 0, len(a.Songs))
  602. for index, song := range a.Songs {
  603. if song != nil || song.Title != "" {
  604. titles = append(titles, song.Title)
  605. if index == 0 {
  606. i.SongTitle = song.Title
  607. }
  608. }
  609. }
  610. i.Desc = strings.Join(titles, ",")
  611. for _, ctg := range a.Ctgs {
  612. tag := &channel.Tag{ID: ctg.ItemID, Name: ctg.ItemVal}
  613. i.Tags = append(i.Tags, tag)
  614. if len(i.Tags) == 2 {
  615. break
  616. }
  617. }
  618. if len(a.Ctgs) != 0 {
  619. id := a.Ctgs[0].ItemID
  620. name := a.Ctgs[0].ItemVal
  621. if len(a.Ctgs) > 1 {
  622. id = a.Ctgs[1].ItemID
  623. name += "·" + a.Ctgs[1].ItemVal
  624. }
  625. i.Tag = &Tag{Name: name, URI: model.FillURI(model.GotoAudioTag, strconv.FormatInt(id, 10), 0, 0, 0, nil) + "?from=tianma"}
  626. }
  627. if a.Type == 5 {
  628. i.Badge = "专辑"
  629. i.Type = 2
  630. } else {
  631. i.Badge = "歌单"
  632. i.Type = 1
  633. }
  634. i.PTime = xtime.Time(a.PaTime)
  635. }
  636. func (i *Item) FromPlayer(a *archive.ArchiveWithPlayer) {
  637. if !a.IsNormal() {
  638. return
  639. }
  640. title := i.Title
  641. if title == "" {
  642. title = a.Title
  643. }
  644. cover := i.Cover
  645. if cover == "" {
  646. cover = a.Pic
  647. }
  648. item := &Item{Title: title, Cover: cover, Param: strconv.FormatInt(a.Aid, 10), Goto: model.GotoAv}
  649. item.URI = model.FillURI(item.Goto, item.Param, 0, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  650. item.fillArcStat(a.Archive3)
  651. i.Item = []*Item{item}
  652. i.Cid = a.FirstCid
  653. i.Rid = a.TypeID
  654. i.TName = a.TypeName
  655. i.Mid = a.Author.Mid
  656. i.Goto = model.GotoPlayer
  657. i.Name = a.Author.Name
  658. i.Face = a.Author.Face
  659. i.Duration = a.Duration
  660. i.Autoplay = a.Rights.Autoplay
  661. }
  662. func (i *Item) FromPlayerLive(r *cardlive.Room) {
  663. if r.LiveStatus == 0 || r.Title == "" || r.Cover == "" {
  664. return
  665. }
  666. i.Name = r.Uname
  667. i.Mid = r.UID
  668. i.Face = r.Face
  669. item := &Item{Title: r.Title, Cover: r.Cover, Param: strconv.FormatInt(r.RoomID, 10), Goto: model.GotoLive, URI: model.FillURI(i.Goto, i.Param, 0, 0, 0, model.LiveRoomHandler(r))}
  670. item.Online = int(r.Online)
  671. item.Area2 = &Area2{ID: r.AreaV2ParentID, Name: r.AreaV2ParentName, Children: &Area2{ID: r.AreaV2ID, Name: r.AreaV2Name}}
  672. i.Item = []*Item{item}
  673. i.Goto = model.GotoPlayer
  674. i.Autoplay = 1
  675. }
  676. func (i *Item) FromLiveUpRcmd(id int64, cs []*cardlive.Card, card map[int64]*account.Card) {
  677. if len(cs) < 2 {
  678. return
  679. }
  680. is := make([]*Item, 0, 2)
  681. for _, c := range cs[:2] {
  682. if c.LiveStatus != 1 {
  683. return
  684. }
  685. it := &Item{}
  686. it.Title = c.Title
  687. it.Cover = c.ShowCover
  688. it.Goto = model.GotoLive
  689. it.Param = strconv.FormatInt(c.RoomID, 10)
  690. it.URI = model.FillURI(it.Goto, it.Param, 0, 0, 0, model.LiveUpHandler(c))
  691. it.Fans = int64(c.Online)
  692. it.Mid = c.UID
  693. it.Name = c.Uname
  694. it.Badge = "直播"
  695. if card, ok := card[it.Mid]; ok {
  696. if card.Official.Role != 0 {
  697. it.Official = &OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
  698. }
  699. }
  700. is = append(is, it)
  701. }
  702. i.Item = is
  703. i.Goto = model.GotoLiveUpRcmd
  704. i.Param = strconv.FormatInt(id, 10)
  705. }
  706. func (i *Item) FromSubscribe(r *operate.Follow, card map[int64]*account.Card, follow map[int64]bool, upStatm map[int64]*relation.Stat, tagm map[int64]*bustag.Tag) {
  707. if r == nil {
  708. return
  709. }
  710. is := make([]*Item, 0, 3)
  711. switch r.Type {
  712. case "upper":
  713. for _, r := range r.Items {
  714. item := &Item{}
  715. if card, ok := card[r.Pid]; ok {
  716. if f, ok := follow[r.Pid]; ok && f {
  717. continue
  718. }
  719. item.Name = card.Name
  720. item.Face = card.Face
  721. item.Mid = card.Mid
  722. if card.Official.Role != 0 {
  723. item.Official = &OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
  724. }
  725. item.IsAtten = 0
  726. if stat, ok := upStatm[r.Pid]; ok {
  727. item.Fans = stat.Follower
  728. }
  729. is = append(is, item)
  730. }
  731. }
  732. i.Kind = "upper"
  733. case "channel_three":
  734. for _, r := range r.Items {
  735. item := &Item{}
  736. tg, ok := tagm[r.Pid]
  737. if !ok || tg.IsAtten == 1 {
  738. continue
  739. }
  740. item.Name = tg.Name
  741. item.Face = tg.Cover
  742. item.Fans = int64(tg.Count.Atten)
  743. item.IsAtten = tg.IsAtten
  744. item.Param = strconv.FormatInt(tg.ID, 10)
  745. if item.Face != "" {
  746. is = append(is, item)
  747. }
  748. }
  749. i.Kind = "channel"
  750. }
  751. if len(is) < 3 {
  752. return
  753. }
  754. i.Item = is[:3]
  755. i.Title = r.Title
  756. i.Param = strconv.FormatInt(r.ID, 10)
  757. i.Goto = model.GotoSubscribe
  758. }
  759. func (i *Item) FromSubscribeChannel(r *recommend.Item, tags map[int64]*tag.Tag) {
  760. if len(tags) == 0 {
  761. return
  762. }
  763. is := []*Item{}
  764. for _, item := range r.Items {
  765. if t, ok := tags[item.ID]; ok {
  766. if t.IsAtten == 1 {
  767. continue
  768. }
  769. tmp := &Item{
  770. Name: t.Name,
  771. Face: t.Cover,
  772. Param: strconv.FormatInt(t.ID, 10),
  773. Fans: int64(t.Count.Atten),
  774. IsAtten: t.IsAtten,
  775. }
  776. is = append(is, tmp)
  777. }
  778. }
  779. if len(is) < 3 {
  780. return
  781. }
  782. i.Item = is[:3]
  783. if r.Config != nil {
  784. i.Title = r.Config.Title
  785. }
  786. i.Param = strconv.FormatInt(r.ID, 10)
  787. i.Kind = "channel"
  788. i.Goto = model.GotoSubscribe
  789. }
  790. func (i *Item) FromChannelRcmd(r *operate.Follow, am map[int64]*archive.ArchiveWithPlayer, tagm map[int64]*bustag.Tag) {
  791. if r == nil {
  792. return
  793. }
  794. if a, ok := am[r.Pid]; ok {
  795. i.Goto = model.GotoChannelRcmd
  796. i.URI = model.FillURI(model.GotoAv, strconv.FormatInt(a.Aid, 10), 0, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  797. i.Title = a.Title
  798. i.Cover = a.Pic
  799. if tag, ok := tagm[r.Tid]; ok {
  800. i.Tag = &Tag{ID: tag.ID, Name: tag.Name, Face: tag.Cover, Fans: tag.Count.Atten, IsAtten: tag.IsAtten}
  801. }
  802. i.Cid = a.FirstCid
  803. i.Autoplay = a.Rights.Autoplay
  804. i.fillArcStat(a.Archive3)
  805. i.Duration = a.Duration
  806. // TODO 等待开启
  807. // percent := i.Like / (i.Like + i.Dislike) * 100
  808. // if percent != 0 {
  809. // i.Desc = strconv.Itoa(percent) + "%的人推荐"
  810. // }
  811. i.Param = strconv.FormatInt(r.ID, 10)
  812. }
  813. }