fix(route/tiktok): fix route (#20648)
* fix(route/tiktok): fix route * fix(route/tiktok): clarify comment on officalItem property
This commit is contained in:
parent
fd98be1027
commit
24612ee4d8
|
|
@ -0,0 +1,273 @@
|
|||
export type Item = {
|
||||
AIGCDescription: string;
|
||||
CategoryType: number;
|
||||
author: {
|
||||
UserStoryStatus: number;
|
||||
avatarLarger: string;
|
||||
avatarMedium: string;
|
||||
avatarThumb: string;
|
||||
commentSetting: number;
|
||||
downloadSetting: number;
|
||||
duetSetting: number;
|
||||
ftc: boolean;
|
||||
id: string;
|
||||
isADVirtual: boolean;
|
||||
isEmbedBanned: boolean;
|
||||
nickname: string;
|
||||
openFavorite: boolean;
|
||||
privateAccount: boolean;
|
||||
relation: number;
|
||||
secUid: string;
|
||||
secret: boolean;
|
||||
signature: string;
|
||||
stitchSetting: number;
|
||||
uniqueId: string;
|
||||
verified: boolean;
|
||||
};
|
||||
authorStats: {
|
||||
diggCount: number;
|
||||
followerCount: number;
|
||||
followingCount: number;
|
||||
friendCount: number;
|
||||
heart: number;
|
||||
heartCount: number;
|
||||
videoCount: number;
|
||||
};
|
||||
authorStatsV2: {
|
||||
diggCount: string;
|
||||
followerCount: string;
|
||||
followingCount: string;
|
||||
friendCount: string;
|
||||
heart: string;
|
||||
heartCount: string;
|
||||
videoCount: string;
|
||||
};
|
||||
backendSourceEventTracking: string;
|
||||
collected: boolean;
|
||||
createTime: number;
|
||||
creatorAIComment: {
|
||||
eligibleVideo: boolean;
|
||||
hasAITopic: boolean;
|
||||
notEligibleReason: number;
|
||||
};
|
||||
desc: string;
|
||||
digged: boolean;
|
||||
duetDisplay: number;
|
||||
duetEnabled: boolean;
|
||||
forFriend: boolean;
|
||||
id: string;
|
||||
isAd: boolean;
|
||||
isReviewing: boolean;
|
||||
itemCommentStatus: number;
|
||||
item_control: {
|
||||
can_repost: boolean;
|
||||
can_comment?: boolean;
|
||||
can_creator_redirect?: boolean;
|
||||
can_music_redirect?: boolean;
|
||||
can_share?: boolean;
|
||||
};
|
||||
music: {
|
||||
authorName: string;
|
||||
coverLarge: string;
|
||||
coverMedium: string;
|
||||
coverThumb: string;
|
||||
duration: number;
|
||||
id: string;
|
||||
isCopyrighted: boolean;
|
||||
is_commerce_music: boolean;
|
||||
is_unlimited_music: boolean;
|
||||
original: boolean;
|
||||
playUrl: string;
|
||||
private: boolean;
|
||||
shoot_duration: number;
|
||||
title: string;
|
||||
tt2dsp: {
|
||||
tt_to_dsp_song_infos: {
|
||||
meta_song_id: string;
|
||||
platform: number;
|
||||
song_id: string;
|
||||
token: {
|
||||
apple_music_token: {
|
||||
developer_token: string;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
};
|
||||
};
|
||||
officalItem: boolean; // Not a typo for "officialItem"
|
||||
originalItem: boolean;
|
||||
privateItem: boolean;
|
||||
secret: boolean;
|
||||
shareEnabled: boolean;
|
||||
stats: {
|
||||
collectCount: number;
|
||||
commentCount: number;
|
||||
diggCount: number;
|
||||
playCount: number;
|
||||
shareCount: number;
|
||||
};
|
||||
statsV2: {
|
||||
collectCount: string;
|
||||
commentCount: string;
|
||||
diggCount: string;
|
||||
playCount: string;
|
||||
repostCount: string;
|
||||
shareCount: string;
|
||||
};
|
||||
stitchDisplay: number;
|
||||
stitchEnabled: boolean;
|
||||
textLanguage: string;
|
||||
textTranslatable: boolean;
|
||||
video: {
|
||||
PlayAddrStruct: {
|
||||
DataSize: number;
|
||||
FileCs: string;
|
||||
FileHash: string;
|
||||
Height: number;
|
||||
Uri: string;
|
||||
UrlKey: string;
|
||||
UrlList: string[];
|
||||
Width: number;
|
||||
};
|
||||
VQScore: string;
|
||||
bitrate: number;
|
||||
bitrateInfo: {
|
||||
Bitrate: number;
|
||||
BitrateFPS: number;
|
||||
CodecType: string;
|
||||
Format: string;
|
||||
GearName: string;
|
||||
MVMAF: string;
|
||||
PlayAddr: {
|
||||
DataSize: number;
|
||||
FileCs: string;
|
||||
FileHash: string;
|
||||
Height: number;
|
||||
Uri: string;
|
||||
UrlKey: string;
|
||||
UrlList: string[];
|
||||
Width: number;
|
||||
};
|
||||
QualityType: number;
|
||||
VideoExtra: string;
|
||||
}[];
|
||||
claInfo: {
|
||||
enableAutoCaption: boolean;
|
||||
hasOriginalAudio: boolean;
|
||||
noCaptionReason?: number;
|
||||
captionInfos?: {
|
||||
captionFormat: string;
|
||||
claSubtitleID: string;
|
||||
expire: string;
|
||||
isAutoGen: boolean;
|
||||
isOriginalCaption: boolean;
|
||||
language: string;
|
||||
languageCode: string;
|
||||
languageID: string;
|
||||
subID: string;
|
||||
subtitleType: string;
|
||||
translationType: string;
|
||||
url: string;
|
||||
urlList: string[];
|
||||
variant: string;
|
||||
}[];
|
||||
captionsType?: number;
|
||||
originalLanguageInfo?: {
|
||||
canTranslateRealTimeNoCheck: boolean;
|
||||
language: string;
|
||||
languageCode: string;
|
||||
languageID: string;
|
||||
};
|
||||
};
|
||||
codecType: string;
|
||||
cover: string;
|
||||
definition: string;
|
||||
downloadAddr: string;
|
||||
duration: number;
|
||||
dynamicCover: string;
|
||||
encodeUserTag: string;
|
||||
encodedType: string;
|
||||
format: string;
|
||||
height: number;
|
||||
id: string;
|
||||
originCover: string;
|
||||
playAddr: string;
|
||||
ratio: string;
|
||||
size: number;
|
||||
videoID: string;
|
||||
videoQuality: string;
|
||||
volumeInfo: {
|
||||
Loudness: number;
|
||||
Peak: number;
|
||||
};
|
||||
width: number;
|
||||
zoomCover: {
|
||||
240: string;
|
||||
480: string;
|
||||
720: string;
|
||||
960: string;
|
||||
};
|
||||
subtitleInfos?: {
|
||||
Format: string;
|
||||
LanguageCodeName: string;
|
||||
LanguageID: string;
|
||||
Size: number;
|
||||
Source: string;
|
||||
Url: string;
|
||||
UrlExpire: number;
|
||||
Version: string;
|
||||
}[];
|
||||
};
|
||||
challenges?: {
|
||||
coverLarger: string;
|
||||
coverMedium: string;
|
||||
coverThumb: string;
|
||||
desc: string;
|
||||
id: string;
|
||||
profileLarger: string;
|
||||
profileMedium: string;
|
||||
profileThumb: string;
|
||||
title: string;
|
||||
}[];
|
||||
textExtra?: Array<{
|
||||
awemeId: string;
|
||||
end: number;
|
||||
hashtagName: string;
|
||||
isCommerce: boolean;
|
||||
start: number;
|
||||
subType: number;
|
||||
type: number;
|
||||
secUid?: string;
|
||||
userId?: string;
|
||||
userUniqueId?: string;
|
||||
}>;
|
||||
videoSuggestWordsList?: {
|
||||
video_suggest_words_struct: {
|
||||
hint_text: string;
|
||||
scene: string;
|
||||
words: Array<{
|
||||
word: string;
|
||||
word_id: string;
|
||||
}>;
|
||||
}[];
|
||||
};
|
||||
diversificationId?: number;
|
||||
contents?: {
|
||||
desc: string;
|
||||
textExtra?: {
|
||||
awemeId: string;
|
||||
end: number;
|
||||
hashtagName: string;
|
||||
isCommerce: boolean;
|
||||
start: number;
|
||||
subType: number;
|
||||
type: number;
|
||||
secUid?: string;
|
||||
userId?: string;
|
||||
userUniqueId?: string;
|
||||
}[];
|
||||
}[];
|
||||
BAInfo?: string;
|
||||
adAuthorization?: boolean;
|
||||
adLabelVersion?: number;
|
||||
};
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import path from 'node:path';
|
||||
|
||||
import { load } from 'cheerio';
|
||||
|
||||
import { config } from '@/config';
|
||||
import type { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
|
|
@ -8,6 +10,8 @@ import puppeteer from '@/utils/puppeteer';
|
|||
import { queryToBoolean } from '@/utils/readable-social';
|
||||
import { art } from '@/utils/render';
|
||||
|
||||
import type { Item } from './types';
|
||||
|
||||
const baseUrl = 'https://www.tiktok.com';
|
||||
|
||||
export const route: Route = {
|
||||
|
|
@ -44,26 +48,36 @@ async function handler(ctx) {
|
|||
const browser = await puppeteer();
|
||||
const page = await browser.newPage();
|
||||
await page.setRequestInterception(true);
|
||||
let itemList = { itemList: [] };
|
||||
page.on('request', (request) => {
|
||||
request.resourceType() === 'document' || request.resourceType() === 'script' ? request.continue() : request.abort();
|
||||
['document', 'script', 'xhr', 'fetch'].includes(request.resourceType()) ? request.continue() : request.abort();
|
||||
});
|
||||
page.on('response', async (response) => {
|
||||
const request = response.request();
|
||||
if (request.url().startsWith('https://www.tiktok.com/api/post/item_list/')) {
|
||||
itemList = await response.json();
|
||||
}
|
||||
});
|
||||
await page.goto(`${baseUrl}/${user}`, {
|
||||
waitUntil: 'networkidle0',
|
||||
});
|
||||
const SIGI_STATE = await page.evaluate(() => window.SIGI_STATE);
|
||||
|
||||
const pageHtml = await page.content();
|
||||
await browser.close();
|
||||
|
||||
const lang = SIGI_STATE.AppContext.lang;
|
||||
const SharingMetaState = SIGI_STATE.SharingMetaState;
|
||||
const ItemModule = SIGI_STATE.ItemModule;
|
||||
const $ = load(pageHtml);
|
||||
const rehydrationData = JSON.parse($('script#__UNIVERSAL_DATA_FOR_REHYDRATION__').text());
|
||||
const userDetail = rehydrationData.__DEFAULT_SCOPE__['webapp.user-detail'];
|
||||
|
||||
return { lang, SharingMetaState, ItemModule };
|
||||
return { itemList, userDetail };
|
||||
},
|
||||
config.cache.routeExpire,
|
||||
false
|
||||
);
|
||||
|
||||
const items = Object.values(data.ItemModule).map((item) => ({
|
||||
const { itemList, userDetail } = data;
|
||||
|
||||
const items = itemList.itemList.map((item: Item) => ({
|
||||
title: item.desc,
|
||||
description: art(path.join(__dirname, 'templates/user.art'), {
|
||||
poster: item.video.cover,
|
||||
|
|
@ -71,18 +85,16 @@ async function handler(ctx) {
|
|||
useIframe,
|
||||
id: item.id,
|
||||
}),
|
||||
author: item.nickname,
|
||||
author: item.author.nickname,
|
||||
pubDate: parseDate(item.createTime, 'X'),
|
||||
link: `${baseUrl}/@${item.author}/video/${item.id}`,
|
||||
category: item.textExtra.map((t) => `#${t.hashtagName}`),
|
||||
link: `${baseUrl}/@${item.author.uniqueId}/video/${item.id}`,
|
||||
}));
|
||||
|
||||
return {
|
||||
title: data.SharingMetaState.value['og:title'],
|
||||
description: data.SharingMetaState.value['og:description'],
|
||||
image: data.SharingMetaState.value['og:image'],
|
||||
title: userDetail.shareMeta.title,
|
||||
description: userDetail.shareMeta.desc,
|
||||
image: userDetail.userInfo.user.avatarLarger,
|
||||
link: `${baseUrl}/${user}`,
|
||||
item: items,
|
||||
language: data.lang,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue