mono/reference/tiktok/files/52471.ad466782_deobfuscated.js
2026-01-29 18:35:51 +01:00

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
});
}
};
}
}]);