feat(route): toutiao video (#17479)
This commit is contained in:
parent
9856a2a2fc
commit
2d1c6cc2e9
|
|
@ -0,0 +1,7 @@
|
|||
<video controls preload="metadata"
|
||||
{{ if poster }}
|
||||
poster="{{ poster }}"
|
||||
{{ /if }}
|
||||
>
|
||||
<source src="{{ url }}" type="video/mp4" />
|
||||
</video>
|
||||
|
|
@ -12,13 +12,19 @@ export interface Feed {
|
|||
cell_ctrls: CellCtrls;
|
||||
cell_flag: number;
|
||||
cell_layout_style: number;
|
||||
/**
|
||||
* 0: video
|
||||
* 32: text (w)
|
||||
* 49: video
|
||||
* 60: article
|
||||
*/
|
||||
cell_type: number;
|
||||
comment_count: number;
|
||||
common_raw_data: string;
|
||||
/**
|
||||
* Appears only if cell_type is 32
|
||||
*/
|
||||
content?: string;
|
||||
content: string;
|
||||
content_decoration: string;
|
||||
control_meta: ControlMeta;
|
||||
cursor: number;
|
||||
|
|
@ -55,7 +61,7 @@ export interface Feed {
|
|||
/**
|
||||
* Appears only if cell_type is 32
|
||||
*/
|
||||
rich_content?: string;
|
||||
rich_content: string;
|
||||
read_count: number;
|
||||
reback_flag: number;
|
||||
repin_count: number;
|
||||
|
|
@ -70,15 +76,22 @@ export interface Feed {
|
|||
title: string;
|
||||
url: string;
|
||||
/**
|
||||
* Appears only if cell_type is 32
|
||||
* Appears only if cell_type is 32, 49(0)
|
||||
*/
|
||||
user?: UserInfo;
|
||||
user: UserInfoCell32 | UserInfoCell49;
|
||||
user_bury: number;
|
||||
user_digg: number;
|
||||
user_info?: UserInfo;
|
||||
/**
|
||||
* Appears only if cell_type is 0, 60
|
||||
*/
|
||||
user_info: UserInfoCell60;
|
||||
user_like: number;
|
||||
user_repin: number;
|
||||
user_repin_time: number;
|
||||
/**
|
||||
* Appears only if cell_type is 0, 49
|
||||
*/
|
||||
video: Video;
|
||||
video_duration: number;
|
||||
video_style: number;
|
||||
image_list: ImageListItem[];
|
||||
|
|
@ -251,6 +264,62 @@ interface UserInteraction {
|
|||
|
||||
type VideoInfo = unknown;
|
||||
|
||||
interface Video {
|
||||
bitrate: number;
|
||||
codec_type: string;
|
||||
definition: string;
|
||||
download_addr: DownloadAddr;
|
||||
duration: number;
|
||||
encode_user_tag: string;
|
||||
file_hash: string;
|
||||
height: number;
|
||||
origin_cover: OriginCover;
|
||||
play_addr: PlayAddr;
|
||||
play_addr_list: PlayAddrListItem[];
|
||||
ratio: string;
|
||||
size: number;
|
||||
url_expire: number;
|
||||
video_id: string;
|
||||
volume: Volume;
|
||||
vtype: string;
|
||||
width: number;
|
||||
}
|
||||
|
||||
interface DownloadAddr {
|
||||
uri: string;
|
||||
url_list: string[];
|
||||
}
|
||||
|
||||
interface OriginCover {
|
||||
uri: string;
|
||||
url_list: string[];
|
||||
}
|
||||
|
||||
interface PlayAddr {
|
||||
uri: string;
|
||||
url_list: string[];
|
||||
}
|
||||
|
||||
interface PlayAddrListItem {
|
||||
bitrate: number;
|
||||
codec_type: string;
|
||||
definition: string;
|
||||
encode_user_tag: string;
|
||||
file_hash: string;
|
||||
play_url_list: string[];
|
||||
quality: string;
|
||||
size: number;
|
||||
url_expire: number;
|
||||
video_quality: number;
|
||||
volume: Volume;
|
||||
vtype: string;
|
||||
}
|
||||
|
||||
interface Volume {
|
||||
Loudness: number;
|
||||
Peak: number;
|
||||
}
|
||||
|
||||
interface LogPb {
|
||||
cell_layout_style: string;
|
||||
group_id_str: string;
|
||||
|
|
@ -267,10 +336,60 @@ interface ShowMore {
|
|||
url: string;
|
||||
}
|
||||
|
||||
interface UserInfo {
|
||||
interface UserInfoCell32 {
|
||||
avatar_url: string;
|
||||
desc: string;
|
||||
id: number;
|
||||
is_blocked: number;
|
||||
is_blocking: number;
|
||||
is_followed: number;
|
||||
is_following: number;
|
||||
is_friend: number;
|
||||
live_info_type: number;
|
||||
medals: unknown;
|
||||
name: string;
|
||||
remark_name: string;
|
||||
schema: string;
|
||||
screen_name: string;
|
||||
theme_day: string;
|
||||
user_auth_info: string;
|
||||
user_decoration: string;
|
||||
user_id: string;
|
||||
user_verified: number;
|
||||
verified_content: string;
|
||||
}
|
||||
|
||||
interface UserInfoCell49 {
|
||||
info: {
|
||||
avatar_uri: string;
|
||||
avatar_url: string;
|
||||
ban_status: boolean;
|
||||
desc: string;
|
||||
media_id: string;
|
||||
name: string;
|
||||
origin_profile_url: boolean;
|
||||
origin_user_id: string;
|
||||
schema: string;
|
||||
user_auth_info: string;
|
||||
user_id: string;
|
||||
user_verified: number;
|
||||
verified_content: string;
|
||||
};
|
||||
relation: {
|
||||
is_followed: number;
|
||||
is_following: number;
|
||||
is_friend: number;
|
||||
};
|
||||
relation_count: {
|
||||
followers_count: number;
|
||||
following_count: number;
|
||||
};
|
||||
user_id: string;
|
||||
}
|
||||
|
||||
interface UserInfoCell60 {
|
||||
avatar_url: string;
|
||||
description: string;
|
||||
desc: string;
|
||||
follow: boolean;
|
||||
name: string;
|
||||
user_auth_info: string;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ import { generate_a_bogus } from './a-bogus';
|
|||
import { Feed } from './types';
|
||||
import RejectError from '@/errors/types/reject';
|
||||
import { config } from '@/config';
|
||||
import path from 'node:path';
|
||||
import { getCurrentPath } from '@/utils/helpers';
|
||||
import { art } from '@/utils/render';
|
||||
|
||||
const __dirname = getCurrentPath(import.meta.url);
|
||||
|
||||
export const route: Route = {
|
||||
path: '/user/token/:token',
|
||||
|
|
@ -52,23 +57,71 @@ async function handler(ctx) {
|
|||
}
|
||||
|
||||
const items = feed.map((item) => {
|
||||
const enclosure = item.large_image_list?.pop();
|
||||
return {
|
||||
title: item.title,
|
||||
description: item.rich_content ?? item.abstract ?? item.content,
|
||||
link: `https://www.toutiao.com/${item.cell_type === 60 ? 'article' : /* 32 */ 'w'}/${item.id}/`,
|
||||
pubDate: parseDate(item.publish_time, 'X'),
|
||||
author: item.user_info?.name ?? item.user?.name ?? item.source,
|
||||
enclosure_url: enclosure?.url,
|
||||
enclosure_type: enclosure?.url ? `image/${new URL(enclosure.url).pathname.split('.').pop()}` : undefined,
|
||||
};
|
||||
switch (item.cell_type) {
|
||||
case 0:
|
||||
case 49: {
|
||||
const video = item.video.play_addr_list.sort((a, b) => b.bitrate - a.bitrate)[0];
|
||||
return {
|
||||
title: item.title,
|
||||
description: art(path.join(__dirname, 'templates', 'video.art'), {
|
||||
poster: item.video.origin_cover.url_list[0],
|
||||
url: item.video.play_addr_list.sort((a, b) => b.bitrate - a.bitrate)[0].play_url_list[0],
|
||||
}),
|
||||
link: `https://www.toutiao.com/video/${item.id}/`,
|
||||
pubDate: parseDate(item.publish_time, 'X'),
|
||||
author: item.user?.info.name ?? item.source,
|
||||
enclosure_url: video?.play_url_list[0],
|
||||
enclosure_type: video?.play_url_list[0] ? 'video/mp4' : undefined,
|
||||
user: {
|
||||
name: item.user?.info.name,
|
||||
avatar: item.user?.info.avatar_url,
|
||||
description: item.user?.info.desc,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// text w/o title
|
||||
case 32: {
|
||||
const enclosure = item.large_image_list?.pop();
|
||||
return {
|
||||
title: item.content?.split('\n')[0],
|
||||
description: item.rich_content,
|
||||
link: `https://www.toutiao.com/w/${item.id}/`,
|
||||
pubDate: parseDate(item.publish_time, 'X'),
|
||||
author: item.user?.name,
|
||||
enclosure_url: enclosure?.url,
|
||||
enclosure_type: enclosure?.url ? `image/${new URL(enclosure.url).pathname.split('.').pop()}` : undefined,
|
||||
user: {
|
||||
name: item.user?.name,
|
||||
avatar: item.user?.avatar_url,
|
||||
description: item.user?.desc,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// text w/ title
|
||||
case 60:
|
||||
default:
|
||||
return {
|
||||
title: item.title,
|
||||
description: item.abstract,
|
||||
link: `https://www.toutiao.com/article/${item.id}/`,
|
||||
pubDate: parseDate(item.publish_time, 'X'),
|
||||
author: item.user_info?.name,
|
||||
user: {
|
||||
name: item.user_info?.name,
|
||||
avatar: item.user_info?.avatar_url,
|
||||
description: item.user_info?.description,
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
title: `${feed[0].user_info?.name ?? feed[0].user?.name ?? feed[0].source}的头条主页 - 今日头条(www.toutiao.com)`,
|
||||
description: feed[0].user_info?.description ?? feed[0].user?.desc,
|
||||
title: `${items[0].user.name}的头条主页 - 今日头条(www.toutiao.com)`,
|
||||
description: items[0].user.description,
|
||||
link: `https://www.toutiao.com/c/user/token/${token}/`,
|
||||
image: feed[0].user_info?.avatar_url ?? feed[0].user?.avatar_url,
|
||||
image: items[0].user.avatar,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue