feed.go 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. package feed
  2. import (
  3. "encoding/json"
  4. "strconv"
  5. "strings"
  6. cdm "go-common/app/interface/main/app-card/model"
  7. "go-common/app/interface/main/app-card/model/card/ai"
  8. "go-common/app/interface/main/app-card/model/card/audio"
  9. "go-common/app/interface/main/app-card/model/card/bangumi"
  10. "go-common/app/interface/main/app-card/model/card/banner"
  11. "go-common/app/interface/main/app-card/model/card/cm"
  12. "go-common/app/interface/main/app-card/model/card/live"
  13. "go-common/app/interface/main/app-card/model/card/operate"
  14. "go-common/app/interface/main/app-card/model/card/rank"
  15. "go-common/app/interface/main/app-card/model/card/show"
  16. "go-common/app/interface/main/app-feed/model"
  17. "go-common/app/interface/main/app-feed/model/dislike"
  18. livemdl "go-common/app/interface/main/app-feed/model/live"
  19. bustag "go-common/app/interface/main/tag/model"
  20. tag "go-common/app/interface/main/tag/model"
  21. article "go-common/app/interface/openplatform/article/model"
  22. account "go-common/app/service/main/account/model"
  23. "go-common/app/service/main/archive/model/archive"
  24. feed "go-common/app/service/main/feed/model"
  25. relation "go-common/app/service/main/relation/model"
  26. episodegrpc "go-common/app/service/openplatform/pgc-season/api/grpc/episode/v1"
  27. xtime "go-common/library/time"
  28. )
  29. const (
  30. _rankTitle = "全站排行榜"
  31. _rankURI = "http://www.bilibili.com/index/rank/all-03.json"
  32. _rankCount = 3
  33. _convergeMinCount = 2
  34. _bangumiRcmdUpdates = 99
  35. )
  36. // Item is feed item, contains av, bangumi, live, banner, feed...
  37. type Item struct {
  38. Title string `json:"title,omitempty"`
  39. Subtitle string `json:"subtitle,omitempty"`
  40. Cover string `json:"cover,omitempty"`
  41. URI string `json:"uri,omitempty"`
  42. Redirect string `json:"redirect,omitempty"`
  43. Param string `json:"param,omitempty"`
  44. Goto string `json:"goto,omitempty"`
  45. Desc string `json:"desc,omitempty"`
  46. Play int `json:"play,omitempty"`
  47. Danmaku int `json:"danmaku,omitempty"`
  48. Reply int `json:"reply,omitempty"`
  49. Fav int `json:"favorite,omitempty"`
  50. Coin int `json:"coin,omitempty"`
  51. Share int `json:"share,omitempty"`
  52. Like int `json:"like,omitempty"`
  53. Dislike int `json:"dislike,omitempty"`
  54. Duration int64 `json:"duration,omitempty"`
  55. Count int `json:"count,omitempty"`
  56. Status int8 `json:"status,omitempty"`
  57. Type int8 `json:"type,omitempty"`
  58. Badge string `json:"badge,omitempty"`
  59. StatType int8 `json:"stat_type,omitempty"`
  60. RcmdReason *RcmdReason `json:"rcmd_reason,omitempty"`
  61. Item []*Item `json:"item,omitempty"`
  62. // sortedset index
  63. Idx int64 `json:"idx,omitempty"`
  64. // av
  65. Cid int64 `json:"cid,omitempty"`
  66. Rid int32 `json:"tid,omitempty"`
  67. TName string `json:"tname,omitempty"`
  68. Tag *Tag `json:"tag,omitempty"`
  69. Button *Button `json:"button,omitempty"`
  70. DisklikeReasons []*dislike.DisklikeReason `json:"dislike_reasons,omitempty"`
  71. CTime xtime.Time `json:"ctime,omitempty"`
  72. Autoplay int32 `json:"autoplay,omitempty"`
  73. // upper
  74. Mid int64 `json:"mid,omitempty"`
  75. Name string `json:"name,omitempty"`
  76. Face string `json:"face,omitempty"`
  77. IsAtten int8 `json:"is_atten,omitempty"`
  78. Fans int64 `json:"fans,omitempty"`
  79. RecCnt int `json:"recent_count,omitempty"`
  80. Recent []*Item `json:"recent,omitempty"`
  81. Official *OfficialInfo `json:"official,omitempty"`
  82. // live
  83. Online int `json:"online,omitempty"`
  84. Area string `json:"area,omitempty"`
  85. AreaID int `json:"area_id,omitempty"`
  86. Area2 *Area2 `json:"area2,omitempty"`
  87. // bangumi
  88. Index string `json:"index,omitempty"`
  89. IndexTitle string `json:"index_title,omitempty"`
  90. CoverMark string `json:"cover_mark,omitempty"`
  91. Finish bool `json:"finish,omitempty"`
  92. LatestIndex string `json:"last_index,omitempty"`
  93. // bangumi ai
  94. Updates int `json:"updates,omitempty"`
  95. // live or bangumi
  96. From int8 `json:"from,omitempty"`
  97. // adviertisement
  98. RequestID string `json:"request_id,omitempty"`
  99. CreativeID int64 `json:"creative_id,omitempty"`
  100. SrcID int `json:"src_id,omitempty"`
  101. IsAd bool `json:"is_ad,omitempty"`
  102. IsAdLoc bool `json:"is_ad_loc,omitempty"`
  103. AdCb string `json:"ad_cb,omitempty"`
  104. ShowURL string `json:"show_url,omitempty"`
  105. ClickURL string `json:"click_url,omitempty"`
  106. ClientIP string `json:"client_ip,omitempty"`
  107. CmMark int64 `json:"cm_mark,omitempty"`
  108. AdIndex int `json:"ad_index,omitempty"`
  109. Extra json.RawMessage `json:"extra,omitempty"`
  110. CardIndex int `json:"card_index,omitempty"`
  111. // tag
  112. Tags []*tag.Tag `json:"tags,omitempty"`
  113. // rank
  114. Cover1 string `json:"cover1,omitempty"`
  115. Cover2 string `json:"cover2,omitempty"`
  116. Cover3 string `json:"cover3,omitempty"`
  117. // banner
  118. BannerItem []*banner.Banner `json:"banner_item,omitempty"`
  119. Hash string `json:"hash,omitempty"`
  120. // article
  121. Covers []string `json:"covers,omitempty"`
  122. Template int `json:"template,omitempty"`
  123. Temple int `json:"temple,omitempty"`
  124. Category *Category `json:"category,omitempty"`
  125. BannerURL string `json:"banner_url,omitempty"`
  126. // game download
  127. Download int32 `json:"download,omitempty"`
  128. BigCover string `json:"big_cover,omitempty"`
  129. // special
  130. HideBadge bool `json:"hide_badge,omitempty"`
  131. Ratio float64 `json:"ratio,omitempty"`
  132. // shopping
  133. City string `json:"city,omitempty"`
  134. PType string `json:"ptype,omitempty"`
  135. Price string `json:"price,omitempty"`
  136. Square string `json:"square,omitempty"`
  137. STime string `json:"stime,omitempty"`
  138. ETime string `json:"etime,omitempty"`
  139. // news
  140. Content string `json:"content,omitempty"`
  141. // subscribe
  142. Kind string `json:"kind,omitempty"`
  143. // audio
  144. SongTitle string `json:"song_title,omitempty"`
  145. // bigdata source
  146. Source string `json:"-"`
  147. AvFeature json.RawMessage `json:"-"`
  148. // common
  149. GotoOrg string `json:"-"`
  150. // rank score
  151. Score string `json:"score,omitempty"`
  152. // ai recommend
  153. AI *ai.Item `json:"-"`
  154. // abtest
  155. AutoplayCard int `json:"autoplay_card,omitempty"`
  156. }
  157. type Dimension struct {
  158. Width int64 `json:"width,omitempty"`
  159. Height int64 `json:"height,omitempty"`
  160. Rotate int64 `json:"rotate,omitempty"`
  161. }
  162. type Button struct {
  163. Name string `json:"name,omitempty"`
  164. URI string `json:"uri,omitempty"`
  165. RedirectURI string `json:"redirect_uri,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 Category struct {
  175. ID int64 `json:"id,omitempty"`
  176. Name string `json:"name,omitempty"`
  177. Children *Category `json:"children,omitempty"`
  178. }
  179. type Area2 struct {
  180. ID int64 `json:"id,omitempty"`
  181. Name string `json:"name,omitempty"`
  182. Children *Area2 `json:"children,omitempty"`
  183. }
  184. type Tag struct {
  185. // new
  186. ID int64 `json:"id,omitempty"`
  187. Name string `json:"name,omitempty"`
  188. Face string `json:"face,omitempty"`
  189. Fans int `json:"fans,omitempty"`
  190. IsAtten int8 `json:"is_atten,omitempty"`
  191. URI string `json:"uri,omitempty"`
  192. // old
  193. TagID int64 `json:"tag_id,omitempty"`
  194. TagName string `json:"tag_name,omitempty"`
  195. Count *TagCount `json:"count,omitempty"`
  196. }
  197. type TagCount struct {
  198. Atten int `json:"atten,omitempty"`
  199. }
  200. type OfficialInfo struct {
  201. Role int8 `json:"role,omitempty"`
  202. Title string `json:"title,omitempty"`
  203. Desc string `json:"desc,omitempty"`
  204. }
  205. type IndexParam struct {
  206. Build int `form:"build"`
  207. Platform string `form:"platform"`
  208. MobiApp string `form:"mobi_app"`
  209. Device string `form:"device"`
  210. Network string `form:"network"`
  211. // idx, err := strconv.ParseInt(idxStr, 10, 64)
  212. // if err != nil || idx < 0 {
  213. // idx = 0
  214. // }
  215. Idx int64 `form:"idx" default:"0"`
  216. // pull, err := strconv.ParseBool(pullStr)
  217. // if err != nil {
  218. // pull = true
  219. // }
  220. Pull bool `form:"pull" default:"true"`
  221. Column cdm.ColumnStatus `form:"column"`
  222. // loginEvent, err := strconv.Atoi(loginEventStr)
  223. // if err != nil {
  224. // loginEvent = 0
  225. // }
  226. LoginEvent int `form:"login_event" default:"0"`
  227. OpenEvent string `form:"open_event"`
  228. BannerHash string `form:"banner_hash"`
  229. AdExtra string `form:"ad_extra"`
  230. Qn int `form:"qn" default:"0"`
  231. Interest string `form:"interest"`
  232. Flush int `form:"flush"`
  233. AutoPlayCard int `form:"autoplay_card"`
  234. Fnver int `form:"fnver" default:"0"`
  235. Fnval int `form:"fnval" default:"0"`
  236. DeviceType int `form:"device_type"`
  237. ParentMode int `form:"parent_mode"`
  238. ForceHost int `form:"force_host"`
  239. RecsysMode int `form:"recsys_mode"`
  240. }
  241. type ConvergeParam struct {
  242. ID int64 `form:"id" validate:"required,min=1"`
  243. MobiApp string `form:"mobi_app"`
  244. Device string `form:"device"`
  245. Build int `form:"build"`
  246. Qn int `form:"qn" default:"0"`
  247. Fnver int `form:"fnver" default:"0"`
  248. Fnval int `form:"fnval" default:"0"`
  249. ForceHost int `form:"force_host"`
  250. }
  251. func (i *Item) FromRcmd(r *ai.Item) {
  252. i.Title = r.Name
  253. i.Param = strconv.FormatInt(r.ID, 10)
  254. if r.Goto == "" {
  255. r.Goto = model.GotoAv
  256. }
  257. i.From = r.From
  258. i.Source = r.Source
  259. i.AvFeature = r.AvFeature
  260. if r.Config != nil {
  261. i.Title = r.Config.Title
  262. i.Cover = r.Config.Cover
  263. i.URI = r.Config.URI
  264. }
  265. i.StatType = r.StatType
  266. i.GotoOrg = r.Goto
  267. }
  268. type Infoc struct {
  269. UserFeature json.RawMessage
  270. IsRcmd bool
  271. NewUser bool
  272. Code int
  273. AutoPlayInfoc string
  274. }
  275. type Config struct {
  276. Column cdm.ColumnStatus `json:"column"`
  277. AutoplayCard int8 `json:"autoplay_card"`
  278. FeedCleanAbtest int8 `json:"feed_clean_abtest"`
  279. FollowMode *FollowMode `json:"follow_mode,omitempty"`
  280. }
  281. type FollowMode struct {
  282. Title string `json:"title,omitempty"`
  283. Option []*Option `json:"option,omitempty"`
  284. Card *Card `json:"-"`
  285. ToastMessage string `json:"toast_message,omitempty"`
  286. }
  287. type Option struct {
  288. Title string `json:"title,omitempty"`
  289. Desc string `json:"desc,omitempty"`
  290. Value int8 `json:"value"`
  291. }
  292. type Card struct {
  293. Title string `json:"-"`
  294. Desc string `json:"-"`
  295. Button []string `json:"-"`
  296. }
  297. func (i *Item) FromAv(a *archive.ArchiveWithPlayer) {
  298. if i.Title == "" {
  299. i.Title = a.Title
  300. }
  301. if i.Cover == "" {
  302. i.Cover = model.CoverURLHTTPS(a.Pic)
  303. } else {
  304. i.Cover = model.CoverURLHTTPS(i.Cover)
  305. }
  306. i.Param = strconv.FormatInt(a.Aid, 10)
  307. i.Goto = model.GotoAv
  308. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  309. i.Cid = a.FirstCid
  310. i.Rid = a.TypeID
  311. i.TName = a.TypeName
  312. i.Desc = strconv.Itoa(int(a.Stat.Danmaku)) + "弹幕"
  313. i.fillArcStat(a.Archive3)
  314. i.Duration = a.Duration
  315. i.Mid = a.Author.Mid
  316. i.Name = a.Author.Name
  317. i.Face = a.Author.Face
  318. i.CTime = a.PubDate
  319. i.Autoplay = a.Rights.Autoplay
  320. }
  321. func (i *Item) FromLive(r *live.Room) {
  322. if r.LiveStatus != 1 || r.Title == "" || r.Cover == "" {
  323. return
  324. }
  325. i.Title = r.Title
  326. i.Cover = r.Cover
  327. i.Goto = model.GotoLive
  328. i.Param = strconv.FormatInt(r.RoomID, 10)
  329. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, model.LiveRoomHandler(r))
  330. i.Name = r.Uname
  331. i.Mid = r.UID
  332. i.Face = r.Face
  333. i.Online = int(r.Online)
  334. i.Autoplay = 1
  335. // i.Area = r.Area
  336. // i.AreaID = r.AreaID
  337. i.Area2 = &Area2{ID: r.AreaV2ParentID, Name: r.AreaV2ParentName, Children: &Area2{ID: r.AreaV2ID, Name: r.AreaV2Name}}
  338. i.Autoplay = 1
  339. }
  340. func (i *Item) FromSeason(b *bangumi.Season) {
  341. if i.Title == "" {
  342. i.Title = b.Title
  343. }
  344. if i.Cover == "" {
  345. i.Cover = b.Cover
  346. }
  347. i.Goto = model.GotoBangumi
  348. i.Param = b.EpisodeID
  349. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, nil)
  350. i.Play = int(b.PlayCount)
  351. i.Fav = int(b.Favorites)
  352. i.Type = b.SeasonType
  353. i.Badge = b.TypeBadge
  354. i.Desc = b.UpdateDesc
  355. i.Face = b.SeasonCover
  356. i.Square = b.SeasonCover
  357. }
  358. func (i *Item) FromPGCSeason(s *episodegrpc.EpisodeCardsProto) {
  359. if i.Title == "" {
  360. i.Title = s.Season.Title
  361. }
  362. if i.Cover == "" {
  363. i.Cover = s.Cover
  364. }
  365. i.Goto = model.GotoBangumi
  366. i.Param = strconv.Itoa(int(s.EpisodeId))
  367. i.URI = model.FillURI(model.GotoBangumi, i.Param, 0, 0, nil)
  368. i.Index = s.Title
  369. i.IndexTitle = s.LongTitle
  370. i.Status = int8(s.Season.SeasonStatus)
  371. i.CoverMark = s.Season.Badge
  372. i.Play = int(s.Season.Stat.View)
  373. i.Fav = int(s.Season.Stat.Follow)
  374. i.Type = int8(s.Season.SeasonType)
  375. i.Badge = s.Season.SeasonTypeName
  376. if s.Season.IsFinish == 1 {
  377. i.Finish = true
  378. }
  379. i.Count = int(s.Season.TotalCount)
  380. i.LatestIndex = s.Title
  381. i.Desc = s.Season.NewEpShow
  382. i.Face = s.Season.Cover
  383. i.Square = s.Season.Cover
  384. }
  385. func (i *Item) FromLogin() {
  386. if i.Param == "0" {
  387. i.Param = "1"
  388. }
  389. i.Goto = model.GotoLogin
  390. }
  391. func (i *Item) FromAdAv(adInfo *cm.AdInfo, a *archive.ArchiveWithPlayer) {
  392. // ad
  393. i.RequestID = adInfo.RequestID
  394. i.CreativeID = adInfo.CreativeID
  395. i.SrcID = adInfo.Source
  396. i.IsAdLoc = adInfo.IsAdLoc
  397. i.IsAd = adInfo.IsAd
  398. i.AdCb = adInfo.AdCb
  399. i.CmMark = adInfo.CmMark
  400. i.AdIndex = adInfo.Index
  401. c := adInfo.CreativeContent
  402. i.Title = c.Title
  403. i.Desc = c.Desc
  404. i.Cover = c.ImageURL
  405. i.Goto = model.GotoAdAv
  406. i.Name = a.Author.Name
  407. i.Face = c.LogURL
  408. i.ShowURL = c.ShowURL
  409. i.ClickURL = c.ClickURL
  410. // archive
  411. i.Param = strconv.FormatInt(a.Aid, 10)
  412. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  413. if a.TypeName != "广告" {
  414. i.TName = a.TypeName
  415. }
  416. i.fillArcStat(a.Archive3)
  417. i.Duration = a.Duration
  418. i.Mid = a.Author.Mid
  419. if i.Name == "" {
  420. i.Name = a.Author.Name
  421. }
  422. if i.Face == "" {
  423. i.Face = a.Author.Face
  424. }
  425. i.CTime = a.Ctime
  426. i.Extra = adInfo.Extra
  427. i.CardIndex = adInfo.CardIndex
  428. }
  429. func (i *Item) FromAdWeb(adInfo *cm.AdInfo) {
  430. i.RequestID = adInfo.RequestID
  431. i.CreativeID = adInfo.CreativeID
  432. i.SrcID = adInfo.Source
  433. i.IsAdLoc = adInfo.IsAdLoc
  434. i.IsAd = adInfo.IsAd
  435. i.AdCb = adInfo.AdCb
  436. i.CmMark = adInfo.CmMark
  437. i.AdIndex = adInfo.Index
  438. c := adInfo.CreativeContent
  439. i.Title = c.Title
  440. i.Desc = c.Desc
  441. i.Cover = c.ImageURL
  442. i.Goto = model.GotoAdWeb
  443. i.URI = model.FillURI(i.Goto, c.URL, 0, 0, nil)
  444. i.ShowURL = c.ShowURL
  445. i.ClickURL = c.ClickURL
  446. i.Extra = adInfo.Extra
  447. i.CardIndex = adInfo.CardIndex
  448. }
  449. func (i *Item) FromAdLarge(adInfo *cm.AdInfo) {
  450. i.RequestID = adInfo.RequestID
  451. i.CreativeID = adInfo.CreativeID
  452. i.SrcID = adInfo.Source
  453. i.IsAdLoc = adInfo.IsAdLoc
  454. i.IsAd = adInfo.IsAd
  455. i.AdCb = adInfo.AdCb
  456. i.CmMark = adInfo.CmMark
  457. i.AdIndex = adInfo.Index
  458. c := adInfo.CreativeContent
  459. i.Title = c.Title
  460. i.Desc = c.Desc
  461. i.Goto = model.GotoAdLarge
  462. i.URI = model.FillURI(i.Goto, c.URL, 0, 0, nil)
  463. i.ShowURL = c.ShowURL
  464. i.ClickURL = c.ClickURL
  465. i.Extra = adInfo.Extra
  466. i.CardIndex = adInfo.CardIndex
  467. }
  468. func (i *Item) FromAdWebS(adInfo *cm.AdInfo) {
  469. i.RequestID = adInfo.RequestID
  470. i.CreativeID = adInfo.CreativeID
  471. i.SrcID = adInfo.Source
  472. i.IsAdLoc = adInfo.IsAdLoc
  473. i.IsAd = adInfo.IsAd
  474. i.AdCb = adInfo.AdCb
  475. i.CmMark = adInfo.CmMark
  476. i.AdIndex = adInfo.Index
  477. c := adInfo.CreativeContent
  478. i.Title = c.Title
  479. i.Desc = c.Desc
  480. i.Cover = c.ImageURL
  481. i.Goto = model.GotoAdWebS
  482. i.URI = model.FillURI(i.Goto, c.URL, 0, 0, nil)
  483. i.ShowURL = c.ShowURL
  484. i.ClickURL = c.ClickURL
  485. i.Extra = adInfo.Extra
  486. i.CardIndex = adInfo.CardIndex
  487. }
  488. func (i *Item) FromSpecial(id int64, title, cover, desc, url string, typ int, badge string, size string) {
  489. if title == "" || cover == "" {
  490. return
  491. }
  492. i.Title = title
  493. i.Cover = cover
  494. i.Goto = model.GotoSpecial
  495. i.URI = model.FillURI(model.OperateType[typ], url, 0, 0, nil)
  496. i.Redirect = model.FillRedirect(i.Goto, typ)
  497. i.Desc = desc
  498. i.Param = strconv.FormatInt(id, 10)
  499. i.HideBadge = true
  500. i.Badge = badge
  501. var ratio float64
  502. if size == "1020x300" {
  503. ratio = 34
  504. } else if size == "1020x378" {
  505. ratio = 27
  506. }
  507. i.Ratio = ratio
  508. }
  509. func (i *Item) FromSpecialS(id int64, title, cover, square, desc, url string, typ int, badge string) {
  510. if title == "" || cover == "" {
  511. return
  512. }
  513. i.Title = title
  514. i.Cover = cover
  515. // 活不过一个版的单列封面
  516. if square != "" {
  517. i.Square = square
  518. } else {
  519. i.Square = cover
  520. }
  521. i.Goto = model.GotoSpecialS
  522. i.URI = model.FillURI(model.OperateType[typ], url, 0, 0, nil)
  523. i.Redirect = model.FillRedirect(i.Goto, typ)
  524. i.Desc = desc
  525. i.Param = strconv.FormatInt(id, 10)
  526. i.Badge = badge
  527. }
  528. func (i *Item) FromRank(ranks []*rank.Rank, am map[int64]*archive.ArchiveWithPlayer) {
  529. if len(ranks) < _rankCount {
  530. return
  531. }
  532. if a, ok := am[ranks[0].Aid]; ok {
  533. i.Cover1 = a.Pic
  534. } else {
  535. return
  536. }
  537. if a, ok := am[ranks[1].Aid]; ok {
  538. i.Cover2 = a.Pic
  539. } else {
  540. return
  541. }
  542. if a, ok := am[ranks[2].Aid]; ok {
  543. i.Cover3 = a.Pic
  544. } else {
  545. return
  546. }
  547. ris := make([]*Item, 0, _rankCount)
  548. for _, rank := range ranks[:_rankCount] {
  549. if a, ok := am[rank.Aid]; ok {
  550. ri := &Item{
  551. Title: a.Title,
  552. Cover: a.Pic,
  553. Goto: model.GotoAv,
  554. Param: strconv.FormatInt(a.Aid, 10),
  555. }
  556. ri.fillArcStat(a.Archive3)
  557. ri.Duration = a.Duration
  558. ri.URI = model.FillURI(ri.Goto, ri.Param, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  559. score := int64(rank.Score)
  560. if score < 10000 {
  561. ri.Score = model.Rounding(score, 0)
  562. } else if score >= 10000 && score < 100000000 {
  563. ri.Score = model.Rounding(score, 10000) + "万"
  564. } else if score >= 100000000 {
  565. ri.Score = model.Rounding(score, 100000000) + "亿"
  566. }
  567. if ri.Score != "" {
  568. ri.Score = "综合评分:" + ri.Score
  569. } else {
  570. ri.Score = "综合评分:-"
  571. }
  572. ris = append(ris, ri)
  573. } else {
  574. return
  575. }
  576. }
  577. i.Title = _rankTitle
  578. i.Goto = model.GotoRank
  579. i.Item = ris
  580. i.Param = "0"
  581. i.URI = model.FillURI(i.Goto, _rankURI, 0, 0, nil)
  582. }
  583. func (i *Item) FromBangumiRcmd(u *bangumi.Update) {
  584. i.Cover = u.SquareCover
  585. i.Goto = model.GotoBangumiRcmd
  586. i.Desc = u.Title
  587. if u.Updates > _bangumiRcmdUpdates {
  588. i.Updates = _bangumiRcmdUpdates
  589. } else {
  590. i.Updates = u.Updates
  591. }
  592. }
  593. func (i *Item) FromBanner(bs []*banner.Banner, hash string) {
  594. i.Goto = model.GotoBanner
  595. i.Hash = hash
  596. i.BannerItem = bs
  597. }
  598. func (i *Item) FromPlayer(a *archive.ArchiveWithPlayer) {
  599. if a.Archive3 == nil || !a.IsNormal() {
  600. return
  601. }
  602. title := i.Title
  603. if title == "" {
  604. title = a.Title
  605. }
  606. cover := i.Cover
  607. if cover == "" {
  608. cover = a.Pic
  609. }
  610. item := &Item{Title: title, Cover: cover, Param: strconv.FormatInt(a.Aid, 10), Goto: model.GotoAv}
  611. item.URI = model.FillURI(item.Goto, item.Param, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  612. item.fillArcStat(a.Archive3)
  613. i.Item = []*Item{item}
  614. i.Cid = a.FirstCid
  615. i.Rid = a.TypeID
  616. i.TName = a.TypeName
  617. i.Mid = a.Author.Mid
  618. i.Goto = model.GotoPlayer
  619. i.Name = a.Author.Name
  620. i.Face = a.Author.Face
  621. i.Duration = a.Duration
  622. i.Autoplay = a.Rights.Autoplay
  623. }
  624. func (i *Item) FromPlayerLive(r *live.Room) {
  625. if r.LiveStatus != 1 || r.Title == "" || r.Cover == "" {
  626. return
  627. }
  628. i.Name = r.Uname
  629. i.Mid = r.UID
  630. i.Face = r.Face
  631. item := &Item{Title: r.Title, Cover: r.Cover, Param: strconv.FormatInt(r.RoomID, 10), Goto: model.GotoLive}
  632. item.URI = model.FillURI(item.Goto, item.Param, 0, 0, model.LiveRoomHandler(r))
  633. item.Online = int(r.Online)
  634. item.Area2 = &Area2{ID: r.AreaV2ParentID, Name: r.AreaV2ParentName, Children: &Area2{ID: r.AreaV2ID, Name: r.AreaV2Name}}
  635. i.Item = []*Item{item}
  636. i.Goto = model.GotoPlayer
  637. i.Autoplay = 1
  638. }
  639. func (i *Item) FromRcmdReason(r *ai.RcmdReason) {
  640. if r != nil {
  641. if r.Style != 0 {
  642. i.RcmdReason = &RcmdReason{ID: r.Style, Content: r.Content, BgColor: r.Grounding, IconLocation: r.Position}
  643. if r.Style == 3 {
  644. i.RcmdReason.Message = i.Name
  645. }
  646. } else {
  647. i.RcmdReason = &RcmdReason{ID: r.ID, Content: r.Content}
  648. }
  649. }
  650. }
  651. func (i *Item) FromGameDownloadS(d *operate.Download, plat int8, build int) {
  652. i.Title = d.Title
  653. i.Cover = d.DoubleCover
  654. i.BigCover = d.Cover
  655. i.Goto = model.GotoGameDownloadS
  656. i.Desc = d.Desc
  657. // TODO fuck game
  658. i.URI = model.FillURI(model.OperateType[d.URLType], d.URLValue, plat, build, nil)
  659. i.Redirect = model.FillRedirect(i.Goto, d.URLType)
  660. i.Face = d.Icon
  661. i.Param = strconv.FormatInt(d.ID, 10)
  662. i.Download = d.Number
  663. if d.Icon != "" {
  664. i.Square = d.Icon
  665. } else {
  666. i.Square = d.Cover
  667. }
  668. }
  669. func (i *Item) FromShoppingS(c *show.Shopping) {
  670. if c.Name == "" || c.URL == "" {
  671. return
  672. }
  673. i.Title = c.Name
  674. i.STime = c.STime
  675. i.ETime = c.ETime
  676. i.City = c.CityName
  677. if len(c.Tags) != 0 {
  678. i.PType = c.Tags[0].TagName
  679. }
  680. i.Param = strconv.FormatInt(c.ID, 10)
  681. // 双列封面
  682. if strings.HasPrefix(c.PerformanceImage, "http:") || strings.HasPrefix(c.PerformanceImage, "https:") {
  683. i.Cover = c.PerformanceImage
  684. } else {
  685. i.Cover = "http:" + c.PerformanceImage
  686. }
  687. // 单列封面
  688. if strings.HasPrefix(c.PerformanceImageP, "http:") || strings.HasPrefix(c.PerformanceImageP, "https:") {
  689. i.Square = c.PerformanceImageP
  690. } else {
  691. i.Square = "http:" + c.PerformanceImageP
  692. }
  693. if i.Cover == "" {
  694. i.Cover = i.Square
  695. }
  696. if i.Cover == "" {
  697. return
  698. }
  699. i.Goto = model.GotoShoppingS
  700. i.URI = model.FillURI(i.Goto, c.URL, 0, 0, nil)
  701. i.Type = c.Type
  702. i.Subtitle = c.Subname
  703. // 漫展需加羊角符
  704. if i.Type == 1 {
  705. i.Price = "¥" + c.Pricelt
  706. } else {
  707. i.Price = c.Pricelt
  708. }
  709. i.Desc = c.Want
  710. }
  711. func (i *Item) FromAudio(a *audio.Audio) {
  712. i.Title = a.Title
  713. i.Cover = a.CoverURL
  714. i.Param = strconv.FormatInt(a.MenuID, 10)
  715. i.Goto = model.GotoAudio
  716. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, model.AudioHandler)
  717. i.Play = int(a.PlayNum)
  718. i.Count = a.RecordNum
  719. i.Fav = int(a.FavoriteNum)
  720. i.Face = a.Face
  721. // old
  722. titles := make([]string, 0, len(a.Songs))
  723. for index, song := range a.Songs {
  724. if song != nil || song.Title != "" {
  725. titles = append(titles, song.Title)
  726. if index == 0 {
  727. i.SongTitle = song.Title
  728. }
  729. }
  730. }
  731. i.Desc = strings.Join(titles, ",")
  732. // new
  733. for _, ctg := range a.Ctgs {
  734. tag := &tag.Tag{ID: ctg.ItemID, Name: ctg.ItemVal}
  735. i.Tags = append(i.Tags, tag)
  736. if len(i.Tags) == 2 {
  737. break
  738. }
  739. }
  740. // new
  741. if len(a.Ctgs) != 0 {
  742. id := a.Ctgs[0].ItemID
  743. name := a.Ctgs[0].ItemVal
  744. if len(a.Ctgs) > 1 {
  745. id = a.Ctgs[1].ItemID
  746. name += "·" + a.Ctgs[1].ItemVal
  747. }
  748. i.Tag = &Tag{Name: name, URI: model.FillURI(model.GotoAudioTag, strconv.FormatInt(id, 10), 0, 0, model.AudioHandler)}
  749. }
  750. if a.Type == 5 {
  751. i.Badge = "专辑"
  752. i.Type = 2
  753. } else {
  754. i.Badge = "歌单"
  755. i.Type = 1
  756. }
  757. i.CTime = xtime.Time(a.PaTime)
  758. }
  759. func (i *Item) FromConverge(c *operate.Converge, am map[int64]*archive.ArchiveWithPlayer, rm map[int64]*live.Room, artm map[int64]*article.Meta) {
  760. if len(c.Items) < _convergeMinCount {
  761. return
  762. }
  763. cis := make([]*Item, 0, len(c.Items))
  764. for _, content := range c.Items {
  765. ci := &Item{Title: content.Title}
  766. switch content.Goto {
  767. case model.GotoAv:
  768. if a, ok := am[content.Pid]; ok && a.Archive3 != nil && a.IsNormal() {
  769. if ci.Title == "" {
  770. ci.Title = a.Title
  771. }
  772. ci.Cover = a.Pic
  773. ci.Goto = model.GotoAv
  774. ci.Param = strconv.FormatInt(a.Aid, 10)
  775. ci.URI = model.FillURI(ci.Goto, ci.Param, 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  776. ci.fillArcStat(a.Archive3)
  777. ci.Duration = a.Duration
  778. cis = append(cis, ci)
  779. }
  780. case model.GotoLive:
  781. if r, ok := rm[content.Pid]; ok {
  782. if r.LiveStatus == 0 || r.Title == "" || r.Cover == "" {
  783. continue
  784. }
  785. if ci.Title == "" {
  786. ci.Title = r.Title
  787. }
  788. ci.Cover = r.Cover
  789. ci.Goto = model.GotoLive
  790. ci.Param = strconv.FormatInt(r.RoomID, 10)
  791. ci.Online = int(r.Online)
  792. ci.URI = model.FillURI(ci.Goto, ci.Param, 0, 0, model.LiveRoomHandler(r))
  793. ci.Badge = "直播"
  794. cis = append(cis, ci)
  795. }
  796. case model.GotoArticle:
  797. if art, ok := artm[content.Pid]; ok {
  798. ci.Title = art.Title
  799. ci.Desc = art.Summary
  800. if len(art.ImageURLs) != 0 {
  801. ci.Cover = art.ImageURLs[0]
  802. }
  803. ci.Goto = model.GotoArticle
  804. ci.Param = strconv.FormatInt(art.ID, 10)
  805. ci.URI = model.FillURI(ci.Goto, ci.Param, 0, 0, nil)
  806. if art.Stats != nil {
  807. ci.fillArtStat(art)
  808. }
  809. ci.Badge = "文章"
  810. cis = append(cis, ci)
  811. }
  812. }
  813. }
  814. if len(cis) < _convergeMinCount {
  815. return
  816. }
  817. i.Item = cis
  818. i.Goto = model.GotoConverge
  819. i.URI = model.FillURI(model.OperateType[c.ReType], c.ReValue, 0, 0, nil)
  820. i.Redirect = model.FillRedirect(i.Goto, c.ReType)
  821. i.Title = c.Title
  822. i.Cover = c.Cover
  823. i.Param = strconv.FormatInt(c.ID, 10)
  824. }
  825. func (i *Item) FromUpBangumi(p *feed.Bangumi) {
  826. i.Title = p.Title
  827. i.Cover = p.NewEp.Cover
  828. i.Goto = model.GotoUpBangumi
  829. i.Param = strconv.FormatInt(p.SeasonID, 10)
  830. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, nil)
  831. i.Status = int8(p.IsFinish)
  832. i.Index = p.NewEp.Index
  833. i.IndexTitle = p.NewEp.IndexTitle
  834. i.Play = int(p.NewEp.Play)
  835. i.Danmaku = int(p.NewEp.Dm)
  836. i.Type = int8(p.BgmType)
  837. i.Count = int(p.TotalCount)
  838. i.Updates = int(p.NewEp.EpisodeID)
  839. i.CTime = xtime.Time(p.Ts)
  840. }
  841. func (i *Item) FromUpLive(f *livemdl.Feed) {
  842. i.Cover = f.Face
  843. i.Param = strconv.FormatInt(f.RoomID, 10)
  844. i.URI = model.FillURI(model.GotoLive, i.Param, 0, 0, nil)
  845. }
  846. func (i *Item) FromUpArticle(m *article.Meta) {
  847. i.Title = m.Title
  848. i.Desc = m.Summary
  849. i.Covers = m.ImageURLs
  850. i.Goto = model.GotoUpArticle
  851. i.Param = strconv.FormatInt(m.ID, 10)
  852. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, nil)
  853. if m.Author != nil {
  854. i.Mid = m.Author.Mid
  855. i.Name = m.Author.Name
  856. i.Face = m.Author.Face
  857. }
  858. if m.Category != nil {
  859. i.Category = &Category{ID: m.Category.ID, Name: m.Category.Name}
  860. }
  861. if m.Stats != nil {
  862. i.fillArtStat(m)
  863. }
  864. i.Temple = int(m.TemplateID)
  865. if i.Temple == 4 {
  866. i.Temple = 1
  867. }
  868. i.Template = int(m.TemplateID)
  869. i.BannerURL = m.BannerURL
  870. i.CTime = m.PublishTime
  871. }
  872. func (i *Item) FromArticleS(m *article.Meta) {
  873. if m.State < 0 {
  874. return
  875. }
  876. i.Title = m.Title
  877. i.Desc = m.Summary
  878. i.Covers = m.ImageURLs
  879. i.Goto = model.GotoArticleS
  880. i.Param = strconv.FormatInt(m.ID, 10)
  881. i.URI = model.FillURI(i.Goto, i.Param, 0, 0, nil)
  882. if m.Author != nil {
  883. i.Mid = m.Author.Mid
  884. i.Name = m.Author.Name
  885. i.Face = m.Author.Face
  886. }
  887. if len(m.Categories) >= 2 && m.Categories[0] != nil && m.Categories[1] != nil {
  888. i.Category = &Category{ID: m.Categories[0].ID, Name: m.Categories[0].Name}
  889. i.Category.Children = &Category{ID: m.Categories[1].ID, Name: m.Categories[1].Name}
  890. }
  891. if m.Stats != nil {
  892. i.fillArtStat(m)
  893. }
  894. i.Temple = int(m.TemplateID)
  895. if i.Temple == 4 {
  896. i.Temple = 1
  897. }
  898. i.Template = int(m.TemplateID)
  899. i.BannerURL = m.BannerURL
  900. i.CTime = m.PublishTime
  901. }
  902. func (i *Item) FromLiveUpRcmd(id int64, cs []*live.Card, card map[int64]*account.Card) {
  903. if len(cs) < 2 {
  904. return
  905. }
  906. is := make([]*Item, 0, 2)
  907. for _, c := range cs[:2] {
  908. if c.LiveStatus != 1 {
  909. return
  910. }
  911. it := &Item{}
  912. it.Title = c.Title
  913. it.Cover = c.ShowCover
  914. it.Goto = model.GotoLive
  915. it.Param = strconv.FormatInt(c.RoomID, 10)
  916. it.URI = model.FillURI(it.Goto, it.Param, 0, 0, model.LiveUpHandler(c))
  917. it.Fans = int64(c.Online)
  918. it.Mid = c.UID
  919. it.Name = c.Uname
  920. it.Badge = "直播"
  921. if card, ok := card[it.Mid]; ok {
  922. if card.Official.Role != 0 {
  923. it.Official = &OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
  924. }
  925. }
  926. is = append(is, it)
  927. }
  928. i.Item = is
  929. i.Goto = model.GotoLiveUpRcmd
  930. i.Param = strconv.FormatInt(id, 10)
  931. }
  932. func (i *Item) FromWeb(title, cover, uri string) {
  933. i.Title = title
  934. i.Cover = cover
  935. i.Goto = model.GotoWeb
  936. i.URI = model.FillURI(i.Goto, uri, 0, 0, nil)
  937. i.Redirect = model.FillRedirect(i.Goto, 0)
  938. }
  939. func (i *Item) FromDislikeReason(plat int8, build int) {
  940. const (
  941. _seasonNoSeason = 1
  942. _seasonRegion = 2
  943. _seasonTag = 3
  944. _seasonUpper = 4
  945. _channelIPhone = 6720
  946. _channelAndroid = 5270000
  947. )
  948. var reasonName string
  949. if (plat == model.PlatIPhone && build > _channelIPhone) || (plat == model.PlatAndroid && build >= _channelAndroid) || plat == model.PlatIPhoneB {
  950. reasonName = "频道:"
  951. } else {
  952. reasonName = "标签:"
  953. }
  954. if i.Tag != nil {
  955. i.DisklikeReasons = []*dislike.DisklikeReason{
  956. &dislike.DisklikeReason{ReasonID: _seasonUpper, ReasonName: "UP主:" + i.Name},
  957. &dislike.DisklikeReason{ReasonID: _seasonRegion, ReasonName: "分区:" + i.TName},
  958. &dislike.DisklikeReason{ReasonID: _seasonTag, ReasonName: reasonName + i.Tag.TagName},
  959. &dislike.DisklikeReason{ReasonID: _seasonNoSeason, ReasonName: "不感兴趣"},
  960. }
  961. } else {
  962. i.DisklikeReasons = []*dislike.DisklikeReason{
  963. &dislike.DisklikeReason{ReasonID: _seasonUpper, ReasonName: "UP主:" + i.Name},
  964. &dislike.DisklikeReason{ReasonID: _seasonRegion, ReasonName: "分区:" + i.TName},
  965. &dislike.DisklikeReason{ReasonID: _seasonNoSeason, ReasonName: "不感兴趣"},
  966. }
  967. }
  968. }
  969. func (i *Item) fillArcStat(a *archive.Archive3) {
  970. if a == nil {
  971. return
  972. }
  973. if a.Access == 0 {
  974. i.Play = int(a.Stat.View)
  975. }
  976. i.Danmaku = int(a.Stat.Danmaku)
  977. i.Reply = int(a.Stat.Reply)
  978. i.Fav = int(a.Stat.Fav)
  979. i.Coin = int(a.Stat.Coin)
  980. i.Share = int(a.Stat.Share)
  981. i.Like = int(a.Stat.Like)
  982. i.Dislike = int(a.Stat.DisLike)
  983. }
  984. func (i *Item) fillArtStat(m *article.Meta) {
  985. if m == nil {
  986. return
  987. }
  988. i.Play = int(m.Stats.View)
  989. i.Reply = int(m.Stats.Reply)
  990. }
  991. func (i *Item) FromTabCards(r *operate.Active, am map[int64]*archive.ArchiveWithPlayer, downm map[int64]*operate.Download, sm map[int64]*bangumi.Season, rm map[int64]*live.Room, metam map[int64]*article.Meta, spm map[int64]*operate.Special) {
  992. items := make([]*Item, 0, len(r.Items))
  993. for _, r := range r.Items {
  994. item := &Item{}
  995. switch r.Goto {
  996. case model.GotoWeb:
  997. item.FromWeb(r.Title, r.Cover, model.FillURI(model.GotoWeb, r.Param, 0, 0, nil))
  998. case model.GotoGame:
  999. if d, ok := downm[r.Pid]; ok {
  1000. item.FromGameDownloadS(d, 0, 0)
  1001. }
  1002. case model.GotoAv:
  1003. if a, ok := am[r.Pid]; ok {
  1004. item.FromAv(a)
  1005. }
  1006. case model.GotoBangumi:
  1007. if b, ok := sm[r.Pid]; ok {
  1008. item.FromSeason(b)
  1009. }
  1010. case model.GotoLive:
  1011. if r, ok := rm[r.Pid]; ok {
  1012. item.FromLive(r)
  1013. }
  1014. case model.GotoArticle:
  1015. if m, ok := metam[r.Pid]; ok {
  1016. item.FromArticleS(m)
  1017. }
  1018. case model.GotoSpecial:
  1019. if sc, ok := spm[r.Pid]; ok {
  1020. item.FromSpecialS(sc.ID, sc.Title, sc.Cover, sc.SingleCover, sc.Desc, sc.ReValue, sc.ReType, sc.Badge)
  1021. }
  1022. }
  1023. if item.Goto != "" {
  1024. items = append(items, item)
  1025. }
  1026. }
  1027. if len(items) == 0 {
  1028. return
  1029. }
  1030. i.Item = items
  1031. i.Title = r.Title
  1032. i.URI = model.FillURI(model.GotoWeb, r.Param, 0, 0, nil)
  1033. i.Subtitle = r.Subtitle
  1034. i.Goto = r.Type
  1035. }
  1036. func (i *Item) FromTabTags(r *operate.Active, am map[int64]*archive.ArchiveWithPlayer, tagm map[int64]*tag.Tag) {
  1037. items := make([]*Item, 0, len(r.Items))
  1038. for _, r := range r.Items {
  1039. if r == nil {
  1040. continue
  1041. }
  1042. item := &Item{}
  1043. switch r.Goto {
  1044. case model.GotoAv:
  1045. if a, ok := am[r.Pid]; ok {
  1046. item.FromAv(a)
  1047. }
  1048. }
  1049. if item.Goto != "" {
  1050. items = append(items, item)
  1051. }
  1052. }
  1053. if len(items) == 0 {
  1054. return
  1055. }
  1056. i.Item = items
  1057. i.Param = strconv.FormatInt(r.Pid, 10)
  1058. if t, ok := tagm[r.Pid]; ok {
  1059. i.Title = t.Name
  1060. }
  1061. i.Goto = r.Type
  1062. }
  1063. func (i *Item) FromTabBanner(r *operate.Active) {
  1064. i.BannerItem = make([]*banner.Banner, 0, len(r.Items))
  1065. for _, item := range r.Items {
  1066. banner := &banner.Banner{ID: item.Pid, Title: item.Title, Image: item.Cover, URI: cdm.FillURI(item.Goto, item.Param, nil)}
  1067. i.BannerItem = append(i.BannerItem, banner)
  1068. }
  1069. i.Goto = model.GotoBanner
  1070. }
  1071. func (i *Item) FromNews(r *operate.Active) {
  1072. if r.Desc == "" {
  1073. return
  1074. }
  1075. i.Title = r.Title
  1076. i.Content = r.Desc
  1077. i.Goto = model.GotoTabNews
  1078. i.URI = model.FillURI(model.GotoWeb, r.Param, 0, 0, nil)
  1079. }
  1080. //最多配10张卡片 取3个未关注的 不足则不显示该卡片
  1081. func (i *Item) FromSubscribe(r *operate.Follow, card map[int64]*account.Card, follow map[int64]bool, statm map[int64]*relation.Stat, tagm map[int64]*bustag.Tag) {
  1082. if r == nil {
  1083. return
  1084. }
  1085. is := make([]*Item, 0, 3)
  1086. switch r.Type {
  1087. case "upper":
  1088. for _, r := range r.Items {
  1089. item := &Item{}
  1090. if card, ok := card[r.Pid]; ok {
  1091. if follow[r.Pid] {
  1092. continue
  1093. }
  1094. item.Name = card.Name
  1095. item.Face = card.Face
  1096. item.Mid = card.Mid
  1097. if card.Official.Role != 0 {
  1098. item.Official = &OfficialInfo{Role: card.Official.Role, Title: card.Official.Title, Desc: card.Official.Desc}
  1099. }
  1100. item.IsAtten = 0
  1101. if stat, ok := statm[r.Pid]; ok {
  1102. item.Fans = stat.Follower
  1103. }
  1104. is = append(is, item)
  1105. }
  1106. }
  1107. i.Kind = "upper"
  1108. case "channel_three":
  1109. for _, r := range r.Items {
  1110. item := &Item{}
  1111. tg, ok := tagm[r.Pid]
  1112. if !ok || tg.IsAtten == 1 {
  1113. continue
  1114. }
  1115. item.Name = tg.Name
  1116. item.Face = tg.Cover
  1117. item.Fans = int64(tg.Count.Atten)
  1118. item.IsAtten = tg.IsAtten
  1119. item.Param = strconv.FormatInt(tg.ID, 10)
  1120. if item.Face != "" {
  1121. is = append(is, item)
  1122. }
  1123. }
  1124. i.Kind = "channel"
  1125. }
  1126. if len(is) < 3 {
  1127. return
  1128. }
  1129. i.Item = is[:3]
  1130. i.Title = r.Title
  1131. i.Param = strconv.FormatInt(r.ID, 10)
  1132. i.Goto = model.GotoSubscribe
  1133. }
  1134. func (i *Item) FromChannelRcmd(r *operate.Follow, am map[int64]*archive.ArchiveWithPlayer, tagm map[int64]*bustag.Tag) {
  1135. if r == nil {
  1136. return
  1137. }
  1138. if a, ok := am[r.Pid]; ok {
  1139. i.Goto = model.GotoChannelRcmd
  1140. i.URI = model.FillURI(model.GotoAv, strconv.FormatInt(a.Aid, 10), 0, 0, model.AvPlayHandler(a.Archive3, a.PlayerInfo))
  1141. i.Title = a.Title
  1142. i.Cover = a.Pic
  1143. if tag, ok := tagm[r.Tid]; ok {
  1144. i.Tag = &Tag{ID: tag.ID, Name: tag.Name, Face: tag.Cover, Fans: tag.Count.Atten, IsAtten: tag.IsAtten}
  1145. }
  1146. i.Cid = a.FirstCid
  1147. i.Autoplay = a.Rights.Autoplay
  1148. i.fillArcStat(a.Archive3)
  1149. i.Duration = a.Duration
  1150. // TODO 等待开启
  1151. // percent := i.Like / (i.Like + i.Dislike) * 100
  1152. // if percent != 0 {
  1153. // i.Desc = strconv.Itoa(percent) + "%的人推荐"
  1154. // }
  1155. i.Param = strconv.FormatInt(r.ID, 10)
  1156. }
  1157. }