@@ -0,0 +1,105 @@
|
||||
import { RELATED_DISPLAY_COUNT } from "@/components/drama-detail/data";
|
||||
import { pickVideoCardTags } from "@/components/common/card-tags";
|
||||
import { formatHeat } from "@/components/ranking/data";
|
||||
import type { ShortDramaItem } from "@/components/short-drama/data";
|
||||
import { mapVideoListItem } from "@/components/video/data";
|
||||
import type {
|
||||
QueryVideoInfoResp,
|
||||
VideoData,
|
||||
VideoDetailInfo,
|
||||
VideoRecommendListResp,
|
||||
} from "@/lib/api/types";
|
||||
import { resolvePlayURL } from "@/lib/media/playback";
|
||||
|
||||
/** 详情页:直接使用接口 videoInfo 字段 */
|
||||
export type VideoDetail = VideoDetailInfo;
|
||||
|
||||
/** H5 / 侧栏热门推荐条数 */
|
||||
export const VIDEO_RECOMMEND_DISPLAY_COUNT = 10;
|
||||
|
||||
export type VideoPlayView = {
|
||||
detail: VideoDetail;
|
||||
src: string;
|
||||
related: ShortDramaItem[];
|
||||
};
|
||||
|
||||
function mapHotVideoItem(item: VideoData): ShortDramaItem {
|
||||
return {
|
||||
kind: "drama",
|
||||
id: String(item.id),
|
||||
slug: item.slug?.trim() || undefined,
|
||||
title: (item.title || "").trim() || "未命名",
|
||||
subtitle: "",
|
||||
tags: pickVideoCardTags(item),
|
||||
heat: formatHeat(item.watchNum),
|
||||
episodes: "",
|
||||
cover: (item.coverImg || "").trim(),
|
||||
};
|
||||
}
|
||||
|
||||
/** 热门推荐:保留广告位;排除当前视频 */
|
||||
export function mapVideoRecommendList(
|
||||
data: VideoRecommendListResp | null | undefined,
|
||||
options?: { excludeId?: number | string | null; limit?: number },
|
||||
): ShortDramaItem[] {
|
||||
const excludeId = options?.excludeId != null ? Number(options.excludeId) : NaN;
|
||||
const limit = options?.limit ?? VIDEO_RECOMMEND_DISPLAY_COUNT;
|
||||
return (data?.list ?? [])
|
||||
.filter((item) => {
|
||||
if (item.type === 2) return true;
|
||||
if (!item.id) return false;
|
||||
if (Number.isFinite(excludeId) && Number(item.id) === excludeId) return false;
|
||||
return true;
|
||||
})
|
||||
.map(mapVideoListItem)
|
||||
.filter((item): item is ShortDramaItem => Boolean(item))
|
||||
.slice(0, limit);
|
||||
}
|
||||
|
||||
/** 透传接口字段,仅拼播放地址 / 根级点赞收藏态 */
|
||||
export function mapVideoInfo(data: QueryVideoInfoResp | null | undefined): VideoPlayView | null {
|
||||
const info = data?.videoInfo;
|
||||
if (!info?.id) return null;
|
||||
|
||||
const media = info.video;
|
||||
const enableH265 = Boolean(data?.config?.enableH265);
|
||||
const path = (enableH265 && media?.h265Url?.trim() ? media.h265Url : media?.url) || media?.h265Url || "";
|
||||
const src = resolvePlayURL(path);
|
||||
|
||||
return {
|
||||
detail: {
|
||||
...info,
|
||||
isLike: Boolean(data?.isLike ?? info.isLike),
|
||||
isFavorite: Boolean(data?.isFavorite ?? info.isFavorite),
|
||||
},
|
||||
src,
|
||||
related: (data?.hotVideoList ?? [])
|
||||
.filter((item) => Boolean(item.id))
|
||||
.slice(0, RELATED_DISPLAY_COUNT)
|
||||
.map(mapHotVideoItem),
|
||||
};
|
||||
}
|
||||
|
||||
export function formatWatchNum(count?: number | null) {
|
||||
const value = Number(count) || 0;
|
||||
if (value >= 10000) {
|
||||
const wan = value / 10000;
|
||||
const text = wan >= 100 ? String(Math.round(wan)) : wan.toFixed(1).replace(/\.0$/, "");
|
||||
return `${text}万次播放`;
|
||||
}
|
||||
return `${value}次播放`;
|
||||
}
|
||||
|
||||
export function formatCount(count?: number | null) {
|
||||
const value = Number(count) || 0;
|
||||
if (value >= 10000) {
|
||||
const wan = value / 10000;
|
||||
const text = wan >= 100 ? String(Math.round(wan)) : wan.toFixed(1).replace(/\.0$/, "");
|
||||
return `${text}万`;
|
||||
}
|
||||
if (value >= 1000) {
|
||||
const k = value / 1000;
|
||||
return `${k.toFixed(1).replace(/\.0$/, "")}k`;
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
Reference in New Issue
Block a user