@@ -236,15 +236,15 @@ function transformWebVideo(item: VideoItem): VideoCardDisplayData {
236236 title: decodeHtmlEntities (item .title ),
237237 cover: item .pic ,
238238 author: {
239- name: decodeHtmlEntities (item .owner .name ),
240- authorFace: item .owner .face ,
239+ name: decodeHtmlEntities (item .owner ? .name || ' ' ),
240+ authorFace: item .owner ? .face || ' ' ,
241241 followed: !! item .is_followed ,
242- mid: item .owner .mid ,
242+ mid: item .owner ? .mid || 0 ,
243243 },
244244 tag: decodeHtmlEntities (item ?.rcmd_reason ?.content ),
245- view: item .stat .view ,
246- danmaku: item .stat .danmaku ,
247- like: item .stat .like ,
245+ view: item .stat ? .view || 0 ,
246+ danmaku: item .stat ? .danmaku || 0 ,
247+ like: item .stat ? .like ,
248248 publishedTimestamp: item .pubdate ,
249249 bvid: item .bvid ,
250250 cid: item .cid ,
@@ -520,20 +520,41 @@ async function getRecommendVideos() {
520520
521521 const beforeLoadCount = videoList .value .filter (video => video .item ).length
522522
523+ // 使用当前的 refreshIdx,只在成功时才递增
524+ const currentRefreshIdx = refreshIdx .value
523525 const response: forYouResult = await api .video .getRecommendVideos ({
524- fresh_idx: refreshIdx . value ++ ,
526+ fresh_idx: currentRefreshIdx ,
525527 ps: PAGE_SIZE ,
526528 })
527529
530+ if (! response ) {
531+ console .error (' Failed to load web recommendations: Response is undefined' )
532+ noMoreContent .value = true
533+ return
534+ }
535+
528536 if (! response .data ) {
529537 noMoreContent .value = true
530538 return
531539 }
532540
533541 if (response .code === 0 ) {
542+ // 只在成功时递增 refreshIdx
543+ refreshIdx .value ++
544+
534545 const resData = [] as VideoItem []
535546
536547 response .data .item .forEach ((item : VideoItem ) => {
548+ // 过滤掉广告卡片
549+ if (item .goto === ' ad' )
550+ return
551+
552+ // 过滤掉缺少必要字段的数据(owner 或 stat 为 null)
553+ if (! item .owner || ! item .stat ) {
554+ console .warn (' [ForYou] Filtered out item with null owner or stat:' , item .id , item .goto )
555+ return
556+ }
557+
537558 if (! filterFunc .value || filterFunc .value (item ))
538559 resData .push (item )
539560 })
@@ -591,12 +612,17 @@ async function getRecommendVideos() {
591612 else if (response .code === 62011 ) {
592613 needToLoginFirst .value = true
593614 }
615+ else {
616+ // 其他错误码也应该停止加载,避免无限重试
617+ console .error (' API returned error code:' , response .code , response .message )
618+ noMoreContent .value = true
619+ }
594620 }
595621 finally {
596622 const filledItems = videoList .value .filter (video => video .item )
597623 videoList .value = filledItems
598624
599- if (! needToLoginFirst .value ) {
625+ if (! needToLoginFirst .value && ! noMoreContent . value ) {
600626 await nextTick ()
601627
602628 const hasScrollbar = await haveScrollbar ()
@@ -627,6 +653,13 @@ async function getAppRecommendVideos() {
627653 return
628654 }
629655
656+ // 检查是否有有效的 access token
657+ if (! appAuthTokens .value .accessToken ) {
658+ console .warn (' APP 推荐模式需要登录,access token 为空' )
659+ needToLoginFirst .value = true
660+ return
661+ }
662+
630663 const batchesToLoad = APP_LOAD_BATCHES .value
631664 const beforeLoadCount = appVideoList .value .length
632665
@@ -646,6 +679,11 @@ async function getAppRecommendVideos() {
646679 idx: lastIdx ,
647680 })
648681
682+ if (! response ) {
683+ console .error (' Failed to load batch' , batch , ' Response is undefined' )
684+ break
685+ }
686+
649687 if (response .code === 0 ) {
650688 response .data .items .forEach ((item : AppVideoItem ) => {
651689 // Remove banner & ad cards
0 commit comments