1432 lines
58 KiB
JavaScript
1432 lines
58 KiB
JavaScript
/**
|
|
* TikTok Video Player - Deobfuscated JavaScript Bundle
|
|
* Original file: 52471.ad466782.js
|
|
*
|
|
* This bundle contains modules for:
|
|
* - Video detail management and state
|
|
* - Subtitle/caption processing (WebVTT)
|
|
* - Video player controls and interactions
|
|
* - Analytics and tracking for video engagement
|
|
* - Infinite scroll and video loading mechanism
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
// Initialize loadable chunks array
|
|
(self.__LOADABLE_LOADED_CHUNKS__ = self.__LOADABLE_LOADED_CHUNKS__ || []).push([["52471"], {
|
|
|
|
/**
|
|
* Module 6424: Video Detail Management
|
|
* Core video player state management and controls
|
|
*/
|
|
6424: function(exports, module, require) {
|
|
require.d(exports, {
|
|
hC: function() { return useVideoDetailService; },
|
|
Dk: function() { return useVideoDetailState; },
|
|
UD: function() { return useVideoDetailDispatchers; }
|
|
});
|
|
|
|
var asyncUtils = require(79066);
|
|
var objectUtils = require(5377);
|
|
var assignUtils = require(45996);
|
|
var generatorUtils = require(72516);
|
|
var httpClient = require(42646);
|
|
var baseUrlTypes = require(56904);
|
|
var itemListKeys = require(38306);
|
|
var seekTypes = require(32878);
|
|
var statusCodes = require(57007);
|
|
var routerUtils = require(17505);
|
|
var appIds = require(51794);
|
|
var miniPlayerUtils = require(78790);
|
|
var atomUtils = require(10625);
|
|
var playModes = require(48859);
|
|
var enterMethods = require(47149);
|
|
var deviceUtils = require(69597);
|
|
var interactionTracking = require(21987);
|
|
var contextUtils = require(35144);
|
|
var itemListUtils = require(72140);
|
|
var itemUtils = require(72702);
|
|
var listHelpers = require(38622);
|
|
var videoPlayerUtils = require(59952);
|
|
var serviceUtils = require(4676);
|
|
var videoApiUtils = require(32540);
|
|
|
|
/**
|
|
* Language code mapping for subtitle support
|
|
*/
|
|
function mapLanguageCode(languageCode) {
|
|
var languageMap = {
|
|
"cmn-Hans-CN": "zh-CN",
|
|
"eng-US": "en-US",
|
|
"jpn-JP": "jp-JP",
|
|
"kor-KR": "ko-KR",
|
|
"cmn-Hans-CN|eng-US": "en-US",
|
|
"rus-RU": "ru-RU",
|
|
"fra-FR": "fr-FR",
|
|
"por-PT": "pt-PT",
|
|
"spa-ES": "es-ES",
|
|
"afr-ZA": "en-ZA",
|
|
"ben-BD": "bn-BD",
|
|
"ces-CZ": "cs-CZ",
|
|
"dan-DK": "da-DK",
|
|
"nld-NL": "nl-NL",
|
|
"fin-FI": "fi-FI",
|
|
"deu-DE": "de-DE",
|
|
"ell-GR": "el-GR",
|
|
"hun-HU": "hu-HU",
|
|
"ind-ID": "id-ID",
|
|
"gle-IE": "en-IE",
|
|
"ita-IT": "it-IT",
|
|
"nor-NO": "no-NO",
|
|
"pol-PL": "pl-PL",
|
|
"swe-SE": "sv-SE",
|
|
"tha-TH": "th-TH",
|
|
"tur-TR": "tr-TR",
|
|
"ara-SA": "ar-SA",
|
|
"fra-CA": "fr-CA",
|
|
"cmn-Hant-CN": "zh-TW",
|
|
"heb-IL": "he-IL",
|
|
"jva-ID": "id-ID",
|
|
"ron-RO": "ro-RO",
|
|
"hin-IN": "hi-IN",
|
|
"ben-IN": "bn-BD",
|
|
"slk-SK": "sk-SK"
|
|
};
|
|
|
|
return languageMap[languageCode] || "en-US";
|
|
}
|
|
|
|
var subtitleFormats = require(85460);
|
|
var webVttUtils = require(48859);
|
|
|
|
/**
|
|
* Video Detail Atom State
|
|
* Central state management for video player
|
|
*/
|
|
var videoDetailAtom = atomUtils.p("videoDetailAtom@tiktok/webapp-desktop", {
|
|
currentIndex: 0, // Current video index in the list
|
|
itemListKey: itemListKeys.Lz.Video, // Key for the item list
|
|
subtitleContent: [], // Parsed subtitle/caption content
|
|
ifShowSubtitle: false, // Whether subtitles are visible
|
|
subtitleStruct: null, // Structured subtitle data
|
|
seekType: seekTypes.RW.None, // Type of seek operation
|
|
playMode: playModes.ey.VideoDetail, // Current play mode
|
|
isScrollGuideVisible: false, // Scroll guide visibility
|
|
isYmlRightPanelVisible: true // Right panel visibility
|
|
});
|
|
|
|
videoDetailAtom.debugLabel = "videoDetailAtom";
|
|
|
|
/**
|
|
* Video Detail Service
|
|
* Service layer for video player operations
|
|
*/
|
|
var videoDetailService = serviceUtils.i(videoDetailAtom, function(getState, setState) {
|
|
return {
|
|
/**
|
|
* Set the current video index
|
|
*/
|
|
setCurrentIndex: function(newIndex) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
currentIndex: newIndex
|
|
}));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set subtitle content array
|
|
*/
|
|
setSubtitleContent: function(subtitleArray) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
subtitleContent: subtitleArray
|
|
}));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Toggle subtitle visibility
|
|
*/
|
|
setIfShowSubtitle: function(isVisible) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
ifShowSubtitle: isVisible
|
|
}));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set structured subtitle data
|
|
*/
|
|
setSubtitleStruct: function(subtitleData) {
|
|
var processedSubtitle = parseSubtitleStruct(subtitleData);
|
|
if (processedSubtitle) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
subtitleStruct: processedSubtitle
|
|
}));
|
|
});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Set seek operation type
|
|
*/
|
|
setSeekType: function(seekType) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
seekType: seekType
|
|
}));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set scroll guide visibility
|
|
*/
|
|
setIsScrollGuideVisible: function(isVisible) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
isScrollGuideVisible: isVisible
|
|
}));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Set right panel visibility
|
|
*/
|
|
setIsYmlRightPanelVisible: function(isVisible) {
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
isYmlRightPanelVisible: isVisible
|
|
}));
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Handle video selection from list
|
|
* Core method for switching between videos in the feed
|
|
*/
|
|
handleSelectVideo: function(selectionParams) {
|
|
return asyncUtils._(function() {
|
|
var newIndex, isAIGCDesc, itemId, itemData, relatedListService,
|
|
itemService, processedItemData;
|
|
|
|
return generatorUtils.__generator(this, function(step) {
|
|
switch (step.label) {
|
|
case 0:
|
|
newIndex = selectionParams.newIndex;
|
|
isAIGCDesc = selectionParams.isAIGCDesc;
|
|
|
|
// Get item ID from browser list at new index
|
|
var browserList = getState(itemListUtils.Hx).browserList || [];
|
|
itemId = browserList[newIndex] || "";
|
|
|
|
// Get item data from state
|
|
itemData = getState(itemUtils.Pu)[itemId];
|
|
|
|
// Get service instances
|
|
relatedListService = itemListUtils.OU();
|
|
itemService = itemUtils.ud();
|
|
|
|
// Process item data for display
|
|
processedItemData = assignUtils._(objectUtils._(objectUtils._({}, itemData), {
|
|
author: {
|
|
nickname: itemData ? itemData.nickname : undefined,
|
|
uniqueId: itemData ? itemData.author : undefined,
|
|
id: itemData ? itemData.authorId : undefined,
|
|
secUid: itemData ? itemData.authorSecId : undefined,
|
|
avatarThumb: itemData ? itemData.avatarThumb : undefined
|
|
}
|
|
}));
|
|
|
|
// Reset related content and subtitles
|
|
relatedListService.resetRelatedList();
|
|
this.setSubtitleContent([]);
|
|
|
|
// Update item with transcript status
|
|
itemService.updateItem({
|
|
id: itemId,
|
|
hasTranscript: false
|
|
});
|
|
|
|
// Update the item list with new video
|
|
listHelpers.Tj(getState, setState, itemListUtils.Hx, itemListKeys.Lz.Video, {
|
|
statusCode: statusCodes.s.Ok,
|
|
itemList: [processedItemData],
|
|
hasMore: true
|
|
});
|
|
|
|
// Update video index and tracking
|
|
this._updateVideoIndex({
|
|
newIndex: 0,
|
|
newId: itemId,
|
|
enterMethod: isAIGCDesc ?
|
|
enterMethods.c.VideoCoverClickAIGCDesc :
|
|
enterMethods.c.VideoCoverClick,
|
|
backendSourceEventTracking: itemData ? itemData.backendSourceEventTracking || "" : ""
|
|
});
|
|
|
|
// Load related videos
|
|
return [4, relatedListService.getRelatedList({
|
|
itemId: itemId,
|
|
secUid: itemData ? itemData.authorSecId : undefined
|
|
})];
|
|
|
|
case 1:
|
|
step.sent();
|
|
return [2];
|
|
}
|
|
});
|
|
}).call(this);
|
|
},
|
|
|
|
/**
|
|
* Handle switching to next/previous video
|
|
* Core infinite scroll mechanism
|
|
*/
|
|
handleSwitchVideo: function(switchParams) {
|
|
return asyncUtils._(function() {
|
|
var newIndex, enterMethod, playStatusUpdate, currentIndex,
|
|
browserList, cannotSwitch, itemId, authorSecId, shouldPreload;
|
|
|
|
return generatorUtils.__generator(this, function(step) {
|
|
switch (step.label) {
|
|
case 0:
|
|
step.trys.push([0, 3, , 4]);
|
|
|
|
// Report video interaction start
|
|
interactionTracking.l.getInstance(deviceUtils.AU)
|
|
.reportVideoInteractStart({
|
|
startTime: Date.now(),
|
|
situation: deviceUtils.uT.VideoDatailSelect
|
|
});
|
|
|
|
newIndex = switchParams.newIndex;
|
|
enterMethod = switchParams.enterMethod !== undefined ?
|
|
switchParams.enterMethod : enterMethods.c.VideoDetailPage;
|
|
playStatusUpdate = switchParams.playStatusUpdate !== undefined ?
|
|
switchParams.playStatusUpdate : true;
|
|
|
|
currentIndex = getState(videoDetailAtom).currentIndex;
|
|
browserList = getState(itemListUtils.Hx).browserList || [];
|
|
|
|
// Validation checks for switching
|
|
cannotSwitch = !browserList.length ||
|
|
newIndex < 0 ||
|
|
newIndex === currentIndex ||
|
|
newIndex >= browserList.length;
|
|
|
|
itemId = browserList[newIndex] || "";
|
|
authorSecId = getState(itemUtils.Pu)[itemId] ?
|
|
getState(itemUtils.Pu)[itemId].authorSecId : undefined;
|
|
|
|
// Check if we need to preload more content
|
|
shouldPreload = (browserList.length - newIndex) < 6;
|
|
|
|
if (cannotSwitch) {
|
|
console.warn("cannot switch to next video for some reasons");
|
|
return [3, 2];
|
|
}
|
|
|
|
// Update video index and clear subtitles
|
|
this._updateVideoIndex({
|
|
newIndex: newIndex,
|
|
newId: itemId,
|
|
enterMethod: enterMethod,
|
|
playStatusUpdate: playStatusUpdate
|
|
});
|
|
|
|
this.setSubtitleContent([]);
|
|
|
|
// Preload related content if needed
|
|
if (shouldPreload && itemId) {
|
|
return [4, itemListUtils.OU().getRelatedList({
|
|
itemId: itemId,
|
|
secUid: authorSecId
|
|
})];
|
|
}
|
|
|
|
return [3, 2];
|
|
|
|
case 1:
|
|
step.sent();
|
|
step.label = 2;
|
|
|
|
case 2:
|
|
return [3, 4];
|
|
|
|
case 3:
|
|
step.sent();
|
|
return [3, 4];
|
|
|
|
case 4:
|
|
return [2];
|
|
}
|
|
});
|
|
}).call(this);
|
|
},
|
|
|
|
/**
|
|
* Handle error refresh - reload current video
|
|
*/
|
|
handleErrorRefresh: function() {
|
|
return asyncUtils._(function() {
|
|
var contextData, abTestVersion, language, currentIndex,
|
|
browserList, itemId, authorSecId, videoEncoding,
|
|
apiResponse, statusCode, itemInfo, relatedListService;
|
|
|
|
return generatorUtils.__generator(this, function(step) {
|
|
switch (step.label) {
|
|
case 0:
|
|
step.trys.push([0, 5, , 6]);
|
|
|
|
// Get context data
|
|
contextData = contextUtils.x();
|
|
abTestVersion = contextData.abTestVersion;
|
|
language = contextData.language;
|
|
|
|
currentIndex = getState(videoDetailAtom).currentIndex;
|
|
browserList = getState(itemListUtils.Hx).browserList || [];
|
|
itemId = browserList[currentIndex];
|
|
authorSecId = getState(itemUtils.Pu)[itemId] ?
|
|
getState(itemUtils.Pu)[itemId].authorSecId : undefined;
|
|
|
|
videoEncoding = routerUtils.oc();
|
|
|
|
// Fetch video data
|
|
return [4, videoApiUtils.d1({
|
|
aid: appIds.xE,
|
|
itemId: itemId,
|
|
language: language,
|
|
clientABVersions: abTestVersion && abTestVersion.versionName ?
|
|
abTestVersion.versionName.split(",") : [],
|
|
video_encoding: videoEncoding
|
|
})];
|
|
|
|
case 1:
|
|
apiResponse = step.sent() || { statusCode: statusCodes.s.UnknownError };
|
|
statusCode = apiResponse.statusCode;
|
|
itemInfo = apiResponse.itemInfo;
|
|
relatedListService = itemListUtils.OU();
|
|
|
|
if (statusCode !== statusCodes.s.Ok) {
|
|
return [3, 2];
|
|
}
|
|
|
|
// Update with fresh data
|
|
var itemStruct = itemInfo ? itemInfo.itemStruct : undefined;
|
|
relatedListService.resetRelatedList();
|
|
|
|
listHelpers.Tj(getState, setState, itemListUtils.Hx, itemListKeys.Lz.Video, {
|
|
statusCode: statusCodes.s.Ok,
|
|
itemList: [itemStruct],
|
|
hasMore: true
|
|
});
|
|
|
|
this.setCurrentIndex(0);
|
|
this._updateVideoIndex({
|
|
newIndex: 0,
|
|
newId: itemId,
|
|
enterMethod: enterMethods.c.VideoErrorAutoReload
|
|
});
|
|
|
|
return [3, 4];
|
|
|
|
case 2:
|
|
// Fallback: load related content
|
|
return [4, relatedListService.getRelatedList({
|
|
itemId: itemId,
|
|
secUid: authorSecId
|
|
})];
|
|
|
|
case 3:
|
|
step.sent();
|
|
step.label = 4;
|
|
|
|
case 4:
|
|
return [3, 6];
|
|
|
|
case 5:
|
|
step.sent();
|
|
return [3, 6];
|
|
|
|
case 6:
|
|
return [2];
|
|
}
|
|
});
|
|
}).call(this);
|
|
},
|
|
|
|
/**
|
|
* Handle first video load
|
|
*/
|
|
handleFirstVideo: function(params) {
|
|
try {
|
|
var enterMethod = params.enterMethod !== undefined ?
|
|
params.enterMethod : enterMethods.c.VideoDetailPage;
|
|
var playMode = params.playMode !== undefined ?
|
|
params.playMode : playModes.ey.VideoDetail;
|
|
|
|
var browserList = getState(itemListUtils.Hx).browserList || [];
|
|
var cannotLoad = !browserList.length || browserList.length <= 0;
|
|
var firstItemId = browserList[0] || "";
|
|
|
|
// Set play mode
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
playMode: playMode
|
|
}));
|
|
});
|
|
|
|
if (cannotLoad) {
|
|
console.warn("cannot switch to first video for some reasons");
|
|
} else {
|
|
this._updateVideoIndex({
|
|
newIndex: 0,
|
|
newId: firstItemId,
|
|
enterMethod: enterMethod
|
|
});
|
|
}
|
|
} catch (error) {
|
|
// Silent error handling
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Handle refresh with specific item ID
|
|
*/
|
|
handleRefreshWithId: function(params) {
|
|
return asyncUtils._(function() {
|
|
var contextData, abTestVersion, language, itemId, authorSecId,
|
|
videoEncoding, apiResponse, statusCode, itemInfo, relatedListService;
|
|
|
|
return generatorUtils.__generator(this, function(step) {
|
|
switch (step.label) {
|
|
case 0:
|
|
step.trys.push([0, 5, , 6]);
|
|
|
|
contextData = contextUtils.x();
|
|
abTestVersion = contextData.abTestVersion;
|
|
language = contextData.language;
|
|
itemId = params.itemId;
|
|
authorSecId = getState(itemUtils.Pu)[itemId] ?
|
|
getState(itemUtils.Pu)[itemId].authorSecId : undefined;
|
|
|
|
videoEncoding = routerUtils.oc();
|
|
|
|
return [4, videoApiUtils.d1({
|
|
aid: appIds.xE,
|
|
itemId: itemId,
|
|
language: language,
|
|
clientABVersions: abTestVersion && abTestVersion.versionName ?
|
|
abTestVersion.versionName.split(",") : [],
|
|
video_encoding: videoEncoding
|
|
})];
|
|
|
|
case 1:
|
|
apiResponse = step.sent() || { statusCode: statusCodes.s.UnknownError };
|
|
statusCode = apiResponse.statusCode;
|
|
itemInfo = apiResponse.itemInfo;
|
|
relatedListService = itemListUtils.OU();
|
|
|
|
if (statusCode !== statusCodes.s.Ok) {
|
|
return [3, 2];
|
|
}
|
|
|
|
var itemStruct = itemInfo ? itemInfo.itemStruct : undefined;
|
|
relatedListService.resetRelatedList();
|
|
|
|
listHelpers.Tj(getState, setState, itemListUtils.Hx, itemListKeys.Lz.Video, {
|
|
statusCode: statusCodes.s.Ok,
|
|
itemList: [itemStruct],
|
|
hasMore: true
|
|
});
|
|
|
|
this.setCurrentIndex(0);
|
|
this._updateVideoIndex({
|
|
newIndex: 0,
|
|
newId: itemId,
|
|
enterMethod: enterMethods.c.CreatorCard
|
|
});
|
|
|
|
return [3, 4];
|
|
|
|
case 2:
|
|
return [4, relatedListService.getRelatedList({
|
|
itemId: itemId,
|
|
secUid: authorSecId
|
|
})];
|
|
|
|
case 3:
|
|
step.sent();
|
|
step.label = 4;
|
|
|
|
case 4:
|
|
return [3, 6];
|
|
|
|
case 5:
|
|
step.sent();
|
|
return [3, 6];
|
|
|
|
case 6:
|
|
return [2];
|
|
}
|
|
});
|
|
}).call(this);
|
|
},
|
|
|
|
/**
|
|
* Download and parse video transcript/subtitles
|
|
*/
|
|
downloadTranscript: function(videoData) {
|
|
return asyncUtils._(function() {
|
|
var currentIndex, browserList, itemId, subtitleContent;
|
|
|
|
return generatorUtils.__generator(this, function(step) {
|
|
switch (step.label) {
|
|
case 0:
|
|
currentIndex = getState(videoDetailAtom).currentIndex;
|
|
browserList = getState(itemListUtils.Hx).browserList || [];
|
|
itemId = browserList[currentIndex] || "";
|
|
|
|
// Parse subtitle data
|
|
return [4, parseSubtitleData(videoData)];
|
|
|
|
case 1:
|
|
subtitleContent = step.sent();
|
|
|
|
// Update state with subtitle content
|
|
this.setSubtitleContent(subtitleContent);
|
|
|
|
// Update item with transcript availability
|
|
itemUtils.ud().updateItem({
|
|
id: itemId,
|
|
hasTranscript: subtitleContent.length > 0
|
|
});
|
|
|
|
return [2];
|
|
}
|
|
});
|
|
}).call(this);
|
|
},
|
|
|
|
/**
|
|
* Internal method to update video index and tracking
|
|
* Critical for maintaining video state and analytics
|
|
*/
|
|
_updateVideoIndex: function(updateParams) {
|
|
var newIndex = updateParams.newIndex;
|
|
var newId = updateParams.newId;
|
|
var enterMethod = updateParams.enterMethod;
|
|
var backendSourceEventTracking = updateParams.backendSourceEventTracking;
|
|
var playStatusUpdate = updateParams.playStatusUpdate;
|
|
|
|
var playMode = getState(videoDetailAtom).playMode;
|
|
var isMiniPlayerShowing = getState(miniPlayerUtils.az).isMiniPlayerShowing;
|
|
|
|
// Update mini player if active
|
|
if (isMiniPlayerShowing && playMode !== playModes.ey.OneColumn) {
|
|
miniPlayerUtils.uZ().updateVideoIndex({
|
|
newId: newId,
|
|
newIndex: newIndex
|
|
});
|
|
}
|
|
|
|
// Prepare video update data
|
|
var videoUpdateData = {
|
|
currentVideo: {
|
|
index: newIndex,
|
|
id: newId,
|
|
mode: isMiniPlayerShowing ? playModes.ey.MiniPlayer : playMode
|
|
},
|
|
playProgress: 0,
|
|
teaParams: {
|
|
isVideoDetail: true,
|
|
enterMethod: enterMethod,
|
|
backendSourceEventTracking: backendSourceEventTracking
|
|
}
|
|
};
|
|
|
|
// Update video player state
|
|
if (playStatusUpdate === undefined || playStatusUpdate) {
|
|
videoPlayerUtils.LM().updateVideo(videoUpdateData);
|
|
}
|
|
|
|
// Update atom state
|
|
setState(videoDetailAtom, function(currentState) {
|
|
return assignUtils._(objectUtils._(objectUtils._({}, currentState), {
|
|
currentIndex: newIndex
|
|
}));
|
|
});
|
|
}
|
|
};
|
|
});
|
|
|
|
/**
|
|
* Parse subtitle structure from video data
|
|
*/
|
|
function parseSubtitleStruct(subtitleInfos) {
|
|
var validSubtitle = subtitleInfos ? subtitleInfos.find(function(subtitle) {
|
|
return (subtitle.Version === "1" || subtitle.Version === "3") &&
|
|
subtitle.Format === subtitleFormats._D.WebVTT;
|
|
}) : null;
|
|
|
|
if (validSubtitle && validSubtitle.Url && validSubtitle.LanguageCodeName) {
|
|
return {
|
|
url: validSubtitle.Url,
|
|
language: mapLanguageCode(validSubtitle.LanguageCodeName),
|
|
expire: validSubtitle.UrlExpire
|
|
};
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Parse subtitle data from API response
|
|
*/
|
|
function parseSubtitleData(videoData) {
|
|
return asyncUtils._(function() {
|
|
var subtitleStruct, currentTime, isExpired, subtitleContent;
|
|
|
|
return generatorUtils.__generator(this, function(step) {
|
|
switch (step.label) {
|
|
case 0:
|
|
subtitleStruct = parseSubtitleStruct(videoData.subtitleInfos);
|
|
currentTime = Math.floor(new Date().getTime() / 1000);
|
|
|
|
if (!subtitleStruct ||
|
|
!subtitleStruct.url ||
|
|
Number(subtitleStruct.expire || 0) <= currentTime) {
|
|
return [2, []];
|
|
}
|
|
|
|
step.label = 1;
|
|
|
|
case 1:
|
|
step.trys.push([1, 3, , 4]);
|
|
|
|
// Fetch subtitle content
|
|
return [4, fetchSubtitleContent(subtitleStruct.url)];
|
|
|
|
case 2:
|
|
subtitleContent = step.sent();
|
|
return [2, subtitleContent ? webVttUtils.ag(subtitleContent).cues : []];
|
|
|
|
case 3:
|
|
step.sent();
|
|
return [2, []];
|
|
|
|
case 4:
|
|
return [2];
|
|
}
|
|
});
|
|
})();
|
|
}
|
|
|
|
/**
|
|
* Fetch subtitle content from URL
|
|
*/
|
|
function fetchSubtitleContent(url) {
|
|
return asyncUtils._(function() {
|
|
return generatorUtils.__generator(this, function(step) {
|
|
return [2, httpClient.h.get(url, {
|
|
baseUrlType: baseUrlTypes.Z4.FixedWww
|
|
})];
|
|
});
|
|
})();
|
|
}
|
|
|
|
// Export service hooks
|
|
var useVideoDetailService = videoDetailService.useAtomService;
|
|
var useVideoDetailDispatchers = videoDetailService.useServiceDispatchers;
|
|
var useVideoDetailState = videoDetailService.useServiceState;
|
|
},
|
|
|
|
/**
|
|
* Module 29781: Video Analytics and Utilities
|
|
* Analytics tracking and video utility functions
|
|
*/
|
|
29781: function(exports, module, require) {
|
|
require.d(exports, {
|
|
Hs: function() { return getVideoMetrics; },
|
|
MA: function() { return getVideoAnalyticsData; },
|
|
Q4: function() { return hasAnchorTypes; },
|
|
Zd: function() { return getAdExtraData; },
|
|
mx: function() { return isImagePost; },
|
|
n5: function() { return isPinnedItem; },
|
|
yy: function() { return getVideoFeatures; }
|
|
});
|
|
|
|
var React = require(40099);
|
|
var selectorUtils = require(11854);
|
|
var timeUtils = require(19960);
|
|
var playModes = require(48859);
|
|
var adUtils = require(50173);
|
|
var userUtils = require(35379);
|
|
var itemUtils = require(72702);
|
|
var contextUtils = require(43264);
|
|
var itemHelpers = require(31926);
|
|
var mlUtils = require(16859);
|
|
|
|
/**
|
|
* Check if content is an image post
|
|
*/
|
|
function isImagePost(itemData) {
|
|
return itemData && itemData.imagePost !== undefined;
|
|
}
|
|
|
|
/**
|
|
* Get analytics data for video
|
|
*/
|
|
function getVideoAnalyticsData(itemData) {
|
|
var isImage = isImagePost(itemData);
|
|
var imageCount = isImage && itemData.imagePost && itemData.imagePost.images ?
|
|
itemData.imagePost.images.length : undefined;
|
|
|
|
return {
|
|
aweme_type: isImage ? 150 : 0,
|
|
pic_cnt: imageCount
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get comprehensive video features for ML and analytics
|
|
*/
|
|
function getVideoFeatures(itemId, nextItemsCount) {
|
|
var itemData = itemHelpers.k(itemId);
|
|
var userData = userUtils.nW(function(state) {
|
|
var authorId = itemData && itemData.author ? itemData.author : "";
|
|
return state.users[authorId];
|
|
}, selectorUtils.bN);
|
|
|
|
var videoData = itemData && itemData.video ? itemData.video : {};
|
|
var videoWidth = videoData.width;
|
|
var videoHeight = videoData.height;
|
|
var videoDuration = videoData.duration;
|
|
var videoRatio = videoData.ratio;
|
|
|
|
var mlFeatures = itemUtils.F3();
|
|
var mlFeatureKeys = React.useMemo(function() {
|
|
return Object.keys(mlFeatures);
|
|
}, [mlFeatures]);
|
|
|
|
var nextVideoInfo = mlUtils.bE(mlFeatureKeys, nextItemsCount);
|
|
|
|
var itemStats = itemData || {};
|
|
var createTime = itemStats.createTime;
|
|
var authorStats = itemStats.authorStats || {};
|
|
var followerCount = authorStats.followerCount || 0;
|
|
var stats = itemStats.stats || {};
|
|
var diggCount = stats.diggCount;
|
|
var playCount = stats.playCount || 0;
|
|
var shareCount = stats.shareCount;
|
|
var commentCount = stats.commentCount;
|
|
var collectCount = stats.collectCount;
|
|
|
|
return {
|
|
video_freshness: timeUtils.QR(Number(createTime || 0)),
|
|
video_duration: videoDuration || 0,
|
|
video_like_history: diggCount || 0,
|
|
video_vv_history: playCount,
|
|
video_share_history: shareCount || 0,
|
|
video_comment_history: commentCount || 0,
|
|
video_favorite_history: Number(collectCount || 0),
|
|
video_resolution: timeUtils.sG(videoRatio || ""),
|
|
video_is_portrait: Number((videoHeight || 0) > (videoWidth || 0)),
|
|
video_100k_vv: Number(playCount >= 100000),
|
|
video_creator_bluev: userData && userData.verified ? 1 : 0,
|
|
video_creator_1k_follower: Number(followerCount >= 1000),
|
|
video_creator_10k_follower: Number(followerCount >= 10000),
|
|
video_creator_100k_follower: Number(followerCount >= 100000),
|
|
video_next_info: JSON.stringify(nextVideoInfo)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get basic video metrics
|
|
*/
|
|
function getVideoMetrics(itemId) {
|
|
var itemData = itemHelpers.k(itemId);
|
|
var videoData = itemData && itemData.video ? itemData.video : {};
|
|
|
|
return {
|
|
video_width: videoData.width,
|
|
video_height: videoData.height,
|
|
video_duration: videoData.duration
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get ad extra data for advertising content
|
|
*/
|
|
function getAdExtraData(params) {
|
|
var itemId = params.id;
|
|
var playMode = params.play_mode !== undefined ? params.play_mode : playModes.Tk.OneColumn;
|
|
|
|
var contextData = contextUtils.W(function() {
|
|
return ["wid"];
|
|
}, []) || {};
|
|
var wid = contextData.wid;
|
|
|
|
var itemData = itemHelpers.k(itemId);
|
|
var adInfo = itemData ? itemData.ad_info : undefined;
|
|
|
|
if (adInfo) {
|
|
var adExtraData = adUtils.n5({
|
|
ad_info: adInfo,
|
|
play_mode: playMode
|
|
});
|
|
adExtraData.ad_extra_data = { user_session: wid };
|
|
return adExtraData;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* Check if item is pinned
|
|
*/
|
|
function isPinnedItem(itemData, isPinned) {
|
|
if (isPinned) {
|
|
return itemData && itemData.isPinnedItem !== undefined && itemData.isPinnedItem;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if video has specific anchor types
|
|
*/
|
|
function hasAnchorTypes(itemData) {
|
|
var anchorTypes = itemData && itemData.AnchorTypes ? itemData.AnchorTypes : [];
|
|
var hasSpecificType = anchorTypes.some(function(anchorType) {
|
|
return anchorType.toString() === "33";
|
|
});
|
|
|
|
var hasPlayAddr = itemData && itemData.video && itemData.video.playAddr;
|
|
|
|
return hasSpecificType && !hasPlayAddr;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Module 85460: WebVTT Subtitle Parser
|
|
* Comprehensive WebVTT subtitle parsing and processing
|
|
*/
|
|
85460: function(exports, module, require) {
|
|
require.d(exports, {
|
|
ag: function() { return parseWebVTT; },
|
|
_D: function() { return SubtitleFormat; },
|
|
IB: function() { return getSubtitleUrl; }
|
|
});
|
|
|
|
var moduleBase = require(48748);
|
|
var classUtils = require(95170);
|
|
var inheritanceUtils = require(7120);
|
|
var errorUtils = require(112);
|
|
|
|
/**
|
|
* Subtitle format enumeration
|
|
*/
|
|
var SubtitleFormat = {
|
|
WebVTT: "webvtt",
|
|
CreatorCaption: "creator_caption"
|
|
};
|
|
|
|
/**
|
|
* WebVTT parsing errors
|
|
*/
|
|
var WebVTTError = function(baseError) {
|
|
function WebVTTError() {
|
|
classUtils._(this, WebVTTError);
|
|
return moduleBase._(this, WebVTTError, arguments);
|
|
}
|
|
inheritanceUtils._(WebVTTError, baseError);
|
|
return WebVTTError;
|
|
}(errorUtils._(Error));
|
|
|
|
var HeaderError = function(baseError) {
|
|
function HeaderError() {
|
|
classUtils._(this, HeaderError);
|
|
return moduleBase._(this, HeaderError, arguments);
|
|
}
|
|
inheritanceUtils._(HeaderError, baseError);
|
|
return HeaderError;
|
|
}(errorUtils._(Error));
|
|
|
|
var BlankLineError = function(baseError) {
|
|
function BlankLineError() {
|
|
classUtils._(this, BlankLineError);
|
|
return moduleBase._(this, BlankLineError, arguments);
|
|
}
|
|
inheritanceUtils._(BlankLineError, baseError);
|
|
return BlankLineError;
|
|
}(errorUtils._(Error));
|
|
|
|
var CueIdentifierError = function(baseError) {
|
|
function CueIdentifierError() {
|
|
classUtils._(this, CueIdentifierError);
|
|
return moduleBase._(this, CueIdentifierError, arguments);
|
|
}
|
|
inheritanceUtils._(CueIdentifierError, baseError);
|
|
return CueIdentifierError;
|
|
}(errorUtils._(Error));
|
|
|
|
var TimestampError = function(baseError) {
|
|
function TimestampError() {
|
|
classUtils._(this, TimestampError);
|
|
return moduleBase._(this, TimestampError, arguments);
|
|
}
|
|
inheritanceUtils._(TimestampError, baseError);
|
|
return TimestampError;
|
|
}(errorUtils._(Error));
|
|
|
|
// Timestamp regex pattern
|
|
var timestampPattern = /([0-9]{1,2})?:?([0-9]{2}):([0-9]{2}\.[0-9]{2,3})/;
|
|
|
|
/**
|
|
* Parse WebVTT subtitle content
|
|
* Comprehensive WebVTT parser with error handling
|
|
*/
|
|
function parseWebVTT(vttContent, options) {
|
|
if (!vttContent || typeof vttContent !== "string") {
|
|
return { cues: [] };
|
|
}
|
|
|
|
options = options || {};
|
|
var includeMeta = options.meta !== undefined ? options.meta : false;
|
|
var strictMode = options.strict !== undefined ? options.strict : true;
|
|
|
|
// Normalize line endings and split into blocks
|
|
var normalizedContent = vttContent.trim()
|
|
.replace(/\r\n/g, "\n")
|
|
.replace(/\r/g, "\n");
|
|
|
|
var blocks = normalizedContent.split("\n\n");
|
|
var header = blocks.shift();
|
|
|
|
// Validate WebVTT header
|
|
if (!header || !header.startsWith("WEBVTT")) {
|
|
throw new WebVTTError('Must start with "WEBVTT"');
|
|
}
|
|
|
|
var headerLines = header.split("\n");
|
|
var headerComment = headerLines[0].replace("WEBVTT", "");
|
|
|
|
// Validate header comment format
|
|
if (headerComment.length > 0 && headerComment[0] !== " " && headerComment[0] !== "\t") {
|
|
throw new HeaderError("Header comment must start with space or tab");
|
|
}
|
|
|
|
// Handle empty content
|
|
if (blocks.length === 0 && headerLines.length === 1) {
|
|
return {
|
|
valid: true,
|
|
strict: strictMode,
|
|
cues: [],
|
|
errors: []
|
|
};
|
|
}
|
|
|
|
// Validate blank line after header
|
|
if (!includeMeta && headerLines.length > 1 && headerLines[1] !== "") {
|
|
throw new BlankLineError("Missing blank line after signature");
|
|
}
|
|
|
|
// Parse cue blocks
|
|
var parseResult = parseCueBlocks(blocks, strictMode);
|
|
var cues = parseResult.cues;
|
|
var errors = parseResult.errors;
|
|
|
|
// Throw first error in strict mode
|
|
if (strictMode && errors.length > 0) {
|
|
throw errors[0];
|
|
}
|
|
|
|
// Parse metadata if requested
|
|
var metadata = null;
|
|
if (includeMeta) {
|
|
var metaObject = {};
|
|
headerLines.slice(1).forEach(function(line) {
|
|
var colonIndex = line.indexOf(":");
|
|
var key = line.slice(0, colonIndex).trim();
|
|
var value = line.slice(colonIndex + 1).trim();
|
|
metaObject[key] = value;
|
|
});
|
|
metadata = Object.keys(metaObject).length > 0 ? metaObject : null;
|
|
}
|
|
|
|
var result = {
|
|
valid: errors.length === 0,
|
|
strict: strictMode,
|
|
cues: cues,
|
|
errors: errors,
|
|
meta: {}
|
|
};
|
|
|
|
if (includeMeta && metadata) {
|
|
result.meta = metadata;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Parse individual cue blocks
|
|
*/
|
|
function parseCueBlocks(blocks, strictMode) {
|
|
var cues = [];
|
|
var errors = [];
|
|
|
|
var parsedCues = blocks.map(function(block, index) {
|
|
try {
|
|
return parseSingleCue(block, index, strictMode);
|
|
} catch (error) {
|
|
errors.push(error);
|
|
return null;
|
|
}
|
|
}).filter(Boolean);
|
|
|
|
return {
|
|
cues: parsedCues,
|
|
errors: errors
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Parse a single WebVTT cue
|
|
*/
|
|
function parseSingleCue(cueBlock, cueIndex, strictMode) {
|
|
var startTime = 0;
|
|
var endTime = 0.01;
|
|
var cueText = "";
|
|
|
|
var lines = cueBlock.split("\n").filter(Boolean);
|
|
|
|
// Skip NOTE blocks
|
|
if (lines.length > 0 && lines[0].trim().startsWith("NOTE")) {
|
|
return null;
|
|
}
|
|
|
|
// Validate cue structure
|
|
if (lines.length === 1 && !lines[0].includes("-->")) {
|
|
throw new CueIdentifierError("Cue identifier cannot be standalone (cue #" + cueIndex + ")");
|
|
}
|
|
|
|
if (lines.length > 1 &&
|
|
!(lines[0].includes("-->") || lines[1].includes("-->"))) {
|
|
throw new CueIdentifierError("Cue identifier needs to be followed by timestamp (cue #" + cueIndex + ")");
|
|
}
|
|
|
|
// Parse timestamp line
|
|
var timestampParts = lines[0].split(" --> ");
|
|
if (timestampParts.length !== 2 ||
|
|
!isValidTimestamp(timestampParts[0]) ||
|
|
!isValidTimestamp(timestampParts[1])) {
|
|
throw new TimestampError("Invalid cue timestamp (cue #" + cueIndex + ")");
|
|
}
|
|
|
|
// Format start time display
|
|
var startTimeParts = timestampParts[0].split(".")[0].split(":");
|
|
var startTimeDisplay = startTimeParts[0] !== "00" ?
|
|
timestampParts[0] :
|
|
startTimeParts[1] + ":" + startTimeParts[2];
|
|
|
|
// Parse timestamps
|
|
startTime = parseTimestamp(timestampParts[0]);
|
|
endTime = parseTimestamp(timestampParts[1]);
|
|
|
|
// Validate timestamp order
|
|
if (strictMode) {
|
|
if (startTime > endTime) {
|
|
throw new TimestampError("Start timestamp greater than end (cue #" + cueIndex + ")");
|
|
}
|
|
if (endTime <= startTime) {
|
|
throw new TimestampError("End must be greater than start (cue #" + cueIndex + ")");
|
|
}
|
|
}
|
|
|
|
if (!strictMode && endTime < startTime) {
|
|
throw new TimestampError("End must be greater or equal to start when not strict (cue #" + cueIndex + ")");
|
|
}
|
|
|
|
// Extract cue text
|
|
lines.shift(); // Remove timestamp line
|
|
cueText = lines.join("\n");
|
|
|
|
if (!cueText) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
start: startTime,
|
|
end: endTime,
|
|
text: cueText,
|
|
startStr: startTimeDisplay
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Validate timestamp format
|
|
*/
|
|
function isValidTimestamp(timestamp) {
|
|
return timestampPattern.test(timestamp);
|
|
}
|
|
|
|
/**
|
|
* Parse timestamp string to seconds
|
|
*/
|
|
function parseTimestamp(timestampString) {
|
|
var matches = timestampString.match(timestampPattern);
|
|
var hours = parseFloat(matches[1] || "0") * 60 * 60;
|
|
var minutes = parseFloat(matches[2]) * 60;
|
|
var seconds = parseFloat(matches[3]);
|
|
|
|
var totalSeconds = hours + minutes + seconds;
|
|
return Number(totalSeconds.toFixed(6));
|
|
}
|
|
|
|
/**
|
|
* Get subtitle URL from subtitle info array
|
|
*/
|
|
function getSubtitleUrl(subtitleInfos, format) {
|
|
format = format !== undefined ? format : SubtitleFormat.WebVTT;
|
|
|
|
var currentTime = Math.floor(new Date().getTime() / 1000);
|
|
|
|
var validSubtitle = subtitleInfos ? subtitleInfos.find(function(subtitle) {
|
|
var expireTime = Number(subtitle.UrlExpire || 0);
|
|
return (subtitle.Version === "1" || subtitle.Version === "3") &&
|
|
expireTime > currentTime &&
|
|
subtitle.Format === format;
|
|
}) : null;
|
|
|
|
return validSubtitle ? validSubtitle.Url : undefined;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Module 95533: Navigation Analytics
|
|
* Analytics tracking for navigation and page transitions
|
|
*/
|
|
95533: function(exports, module, require) {
|
|
require.d(exports, {
|
|
q: function() { return navigationAnalytics; }
|
|
});
|
|
|
|
var objectUtils = require(5377);
|
|
var assignUtils = require(45996);
|
|
var teaAnalytics = require(77226);
|
|
var storageUtils = require(67503);
|
|
var storageKeys = require(60724);
|
|
var enterMethods = require(47149);
|
|
var liveAnalytics = require(47149);
|
|
|
|
/**
|
|
* Navigation Analytics Service
|
|
* Comprehensive tracking for user navigation patterns
|
|
*/
|
|
var navigationAnalytics = {
|
|
/**
|
|
* Track hashtag detail page entry
|
|
*/
|
|
handleEnterTagDetail: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_tag_detail", params);
|
|
},
|
|
|
|
/**
|
|
* Track music detail page entry
|
|
*/
|
|
handleEnterMusicDetail: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_music_detail", params);
|
|
},
|
|
|
|
/**
|
|
* Track discovery page entry
|
|
*/
|
|
handleDiscoveryPage: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_discovery_page", params);
|
|
},
|
|
|
|
/**
|
|
* Track topics page entry
|
|
*/
|
|
handleEnterTopic: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_topics_page", params);
|
|
},
|
|
|
|
/**
|
|
* Track trending page entry
|
|
*/
|
|
handleEnterTrending: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_homepage_hot", params);
|
|
},
|
|
|
|
/**
|
|
* Track user profile entry
|
|
*/
|
|
handleEnterUser: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_personal_detail", params);
|
|
|
|
// Store group ID for tracking
|
|
if (params.group_id !== undefined) {
|
|
storageUtils.J2(storageKeys.DK, params.group_id);
|
|
} else {
|
|
storageUtils.X(storageKeys.DK);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Track profile homepage entry
|
|
*/
|
|
handleEnterProfile: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_personal_homepage", params);
|
|
},
|
|
|
|
/**
|
|
* Track video detail page entry
|
|
*/
|
|
handleEnterVideo: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_video_detail", params);
|
|
},
|
|
|
|
/**
|
|
* Track Q&A detail page entry
|
|
*/
|
|
handleEnterQuestion: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_qa_detail_page", params);
|
|
},
|
|
|
|
/**
|
|
* Track settings page entry
|
|
*/
|
|
handleEnterSet: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_setting_page", params);
|
|
},
|
|
|
|
/**
|
|
* Track following page entry
|
|
*/
|
|
handleEnterFollowing: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_homepage_follow", params);
|
|
},
|
|
|
|
/**
|
|
* Track suicide prevention page entry
|
|
*/
|
|
handleEnterSuicidePrevention: function(params) {
|
|
teaAnalytics.f.sendEvent("tns_show_ssh_tips_support_page", params);
|
|
},
|
|
|
|
/**
|
|
* Track live detail page entry
|
|
*/
|
|
handleEnterLive: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_live_detail", params);
|
|
},
|
|
|
|
/**
|
|
* Track business suite entry
|
|
*/
|
|
handleEnterBusiness: function() {
|
|
teaAnalytics.f.sendEvent("enter_business_suite");
|
|
},
|
|
|
|
/**
|
|
* Track live discover page entry
|
|
*/
|
|
handleEnterLiveDiscover: function(params) {
|
|
teaAnalytics.f.event("enter_live_discover", assignUtils._(objectUtils._(objectUtils._({}, params), {
|
|
click_type: params.click_type ? params.click_type : "enter_live"
|
|
}));
|
|
},
|
|
|
|
/**
|
|
* Track keyboard shortcut settings entry
|
|
*/
|
|
handleEnterKeyboardShortcut: function() {
|
|
teaAnalytics.f.sendEvent("enter_keyboard_setting");
|
|
},
|
|
|
|
/**
|
|
* Track message page entry
|
|
*/
|
|
handleEnterMessage: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_homepage_message", objectUtils._({
|
|
enter_method: enterMethods.c.ClickButton
|
|
}, params));
|
|
},
|
|
|
|
/**
|
|
* Track music playlist entry
|
|
*/
|
|
handleEnterMusicPlaylist: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_live_discover", params);
|
|
},
|
|
|
|
/**
|
|
* Track Q&A detail page entry (alternative)
|
|
*/
|
|
handleEnterQADetailPage: function(params) {
|
|
teaAnalytics.f.sendEvent("enter_qa_detail_page", params);
|
|
},
|
|
|
|
/**
|
|
* Track POI (Point of Interest) detail entry
|
|
*/
|
|
handleEnterPoi: function(params) {
|
|
var enterMethod = params.enter_method;
|
|
var playMode = params.play_mode;
|
|
var authorId = params.author_id;
|
|
var groupId = params.group_id;
|
|
var poiId = params.id;
|
|
var poiType = params.type;
|
|
var cityCode = params.cityCode;
|
|
var countryCode = params.countryCode;
|
|
var typeCode = params.typeCode;
|
|
var isClaimed = params.isClaimed;
|
|
var ttTypeCode = params.ttTypeCode;
|
|
var ttTypeNameMedium = params.ttTypeNameMedium;
|
|
var ttTypeNameSuper = params.ttTypeNameSuper;
|
|
var ttTypeNameTiny = params.ttTypeNameTiny;
|
|
|
|
teaAnalytics.f.sendEvent("enter_poi_detail", {
|
|
enter_method: enterMethod,
|
|
play_mode: playMode,
|
|
author_id: authorId,
|
|
group_id: groupId,
|
|
poi_id: poiId,
|
|
poi_detail_type: liveAnalytics.Af[poiType || 0],
|
|
is_claimed: Number(!!isClaimed),
|
|
poi_city: cityCode,
|
|
poi_region_code: countryCode,
|
|
tt_poi_backend_type: ttTypeNameSuper + "," + ttTypeNameMedium + "," + ttTypeNameTiny + "|" + ttTypeCode,
|
|
poi_type_code: typeCode
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Track explore page entry
|
|
*/
|
|
handleEnterExplore: function(params) {
|
|
var enterMethod = params.enter_method;
|
|
teaAnalytics.f.sendEvent("enter_explore_page", {
|
|
enter_method: enterMethod
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Track friends page entry
|
|
*/
|
|
handleEnterFriends: function(params) {
|
|
var enterMethod = params.enter_method;
|
|
teaAnalytics.f.sendEvent("enter_friends_page", {
|
|
enter_method: enterMethod
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
}]);
|