"use strict"; (() => { // src/shared/rate-normalizer.ts function normalizeFractionRateDisplay(value) { const numericValue = Number(value); if (!Number.isFinite(numericValue)) { return null; } const percentageValue = numericValue * 100; return `${trimTrailingZeros(percentageValue.toFixed(6))}%`; } function trimTrailingZeros(value) { return value.replace(/\.?0+$/, ""); } // src/content/market/market-list-request-snapshot.ts var MARKET_REQUEST_SNAPSHOT_ATTRIBUTE = "data-sces-market-request-snapshot"; function writeMarketListRequestSnapshot(document2, snapshot) { document2.documentElement.setAttribute( MARKET_REQUEST_SNAPSHOT_ATTRIBUTE, JSON.stringify(snapshot) ); } // src/content/market/market-list-row.ts var PAGE_NUMBER_KEYS = [ "currentPage", "page", "pageNo", "pageNum", "page_no", "page_num" ]; var PAGE_SIZE_KEYS = [ "limit", "pageSize", "page_size", "size" ]; var TOTAL_COUNT_KEYS = [ "total", "totalCount", "total_count" ]; var TOTAL_PAGE_KEYS = [ "pageCount", "page_count", "totalPage", "totalPages", "total_page", "total_pages" ]; function mapMarketListRow(row) { const attributeDatas = readMarketAttributeDatas(row); const singleVideoAfterSearchRate = normalizeMarketListRate( readMarketFieldValue(row, attributeDatas, "avg_search_after_view_rate_30d") ); return { authorId: readString(readMarketFieldValue(row, attributeDatas, "star_id")) ?? readString(readMarketFieldValue(row, attributeDatas, "id")) ?? "", authorName: readString(readMarketFieldValue(row, attributeDatas, "nickname")) ?? readString(readMarketFieldValue(row, attributeDatas, "nick_name")) ?? "", coreUserId: readString(readMarketFieldValue(row, attributeDatas, "core_user_id")) ?? void 0, exportFields: buildMarketExportFieldFallbacks(row, attributeDatas), hasDirectRatesSource: true, location: readMarketLocation(row, attributeDatas), price21To60s: readMarketPrice21To60s(row, attributeDatas), rates: singleVideoAfterSearchRate ? { singleVideoAfterSearchRate } : void 0 }; } function parseMarketListResponse(payload) { const container = findMarketListContainer(payload); if (!container) { return null; } const marketList = readMarketListArray(container); if (!marketList) { return null; } return { currentPage: readKnownNumberDeep(container, PAGE_NUMBER_KEYS) ?? void 0, pageSize: readKnownNumberDeep(container, PAGE_SIZE_KEYS) ?? void 0, records: marketList.map((row) => isRecord(row) ? mapMarketListRow(row) : null).filter( (row) => row !== null && Boolean(row.authorId || row.authorName) ), totalCount: readKnownNumberDeep(container, TOTAL_COUNT_KEYS) ?? void 0, totalPages: readKnownNumberDeep(container, TOTAL_PAGE_KEYS) ?? void 0 }; } function findMarketListContainer(value) { const queue = [value]; while (queue.length > 0) { const current = queue.shift(); if (!isRecord(current)) { continue; } if (readMarketListArray(current)) { return current; } Object.values(current).forEach((entry) => { queue.push(unwrapVueRef(entry)); }); } return null; } function readMarketListArray(record) { const marketList = unwrapVueRef(record.marketList); if (Array.isArray(marketList)) { return marketList; } const authors = unwrapVueRef(record.authors); if (Array.isArray(authors)) { return authors; } return null; } function unwrapVueRef(value) { if (isRecord(value) && "value" in value) { return value.value; } return value; } function isRecord(value) { return typeof value === "object" && value !== null; } function readMarketAttributeDatas(record) { return isRecord(record.attribute_datas) ? record.attribute_datas : {}; } function readMarketFieldValue(record, attributeDatas, field) { return record[field] ?? attributeDatas[field]; } function readString(value) { return typeof value === "string" ? value : null; } function normalizeMarketListRate(value) { if (typeof value === "number") { return normalizeFractionRateDisplay(String(value)); } return typeof value === "string" ? normalizeFractionRateDisplay(value) : null; } function normalizeExportCellText(value) { return value?.replace(/\s+/g, " ").trim() ?? ""; } function buildMarketExportFieldFallbacks(record, attributeDatas) { const exportFields = {}; const authorInfo = buildMarketAuthorInfo(record, attributeDatas); const authorType = buildMarketAuthorType(record, attributeDatas); const contentTheme = buildMarketContentTheme(record, attributeDatas); const connectedUsers = formatWanValue( readNumericValue(readMarketFieldValue(record, attributeDatas, "link_link_cnt_by_industry")) ); const followerCount = formatWanValue( readNumericValue(readMarketFieldValue(record, attributeDatas, "follower")) ); const expectedCpm = formatDecimalDisplay( readNumericValue(readMarketFieldValue(record, attributeDatas, "prospective_20_60_cpm")) ); const expectedPlayCount = formatWanValue( readNumericValue(readMarketFieldValue(record, attributeDatas, "expected_play_num")) ); const interactionRate = formatFractionPercent( readNumericValue(readMarketFieldValue(record, attributeDatas, "interact_rate_within_30d")) ); const finishRate = formatFractionPercent( readNumericValue(readMarketFieldValue(record, attributeDatas, "play_over_rate_within_30d")) ); const burstRate = readBurstRateDisplay( readNumericValue(readMarketFieldValue(record, attributeDatas, "burst_text_rate")) ); const price21To60s = readMarketPrice21To60s(record, attributeDatas); const representativeVideo = readMarketRepresentativeVideo(record, attributeDatas); assignExportField(exportFields, "\u8FBE\u4EBA\u4FE1\u606F", authorInfo); assignExportField(exportFields, "\u4EE3\u8868\u89C6\u9891", representativeVideo); assignExportField(exportFields, "\u8FBE\u4EBA\u7C7B\u578B", authorType); assignExportField(exportFields, "\u5185\u5BB9\u4E3B\u9898", contentTheme); assignExportField(exportFields, "\u8FDE\u63A5\u7528\u6237\u6570", connectedUsers); assignExportField(exportFields, "\u7C89\u4E1D\u6570", followerCount); assignExportField(exportFields, "\u9884\u671FCPM", expectedCpm); assignExportField(exportFields, "\u9884\u671F\u64AD\u653E\u91CF", expectedPlayCount); assignExportField(exportFields, "\u4E92\u52A8\u7387", interactionRate); assignExportField(exportFields, "\u5B8C\u64AD\u7387", finishRate); assignExportField(exportFields, "\u7206\u6587\u7387", burstRate); assignExportField(exportFields, "21-60s\u62A5\u4EF7", price21To60s); return Object.keys(exportFields).length > 0 ? exportFields : void 0; } function assignExportField(exportFields, key, value) { if (hasTextValue(value)) { exportFields[key] = value; } } function hasTextValue(value) { return Boolean(value && value.trim().length > 0); } function buildMarketAuthorInfo(record, attributeDatas) { const nickname = readString(readMarketFieldValue(record, attributeDatas, "nickname")) ?? readString(readMarketFieldValue(record, attributeDatas, "nick_name")) ?? ""; const parts = [ nickname, readMarketGenderLabel(readMarketFieldValue(record, attributeDatas, "gender")), readString(readMarketFieldValue(record, attributeDatas, "city")) ?? "" ].filter((value) => Boolean(value)); return parts.length > 0 ? parts.join(" ") : void 0; } function buildMarketAuthorType(record, attributeDatas) { const tagsRelation = readRecordLike( readMarketFieldValue(record, attributeDatas, "tags_relation") ); if (tagsRelation) { const primaryTag = Object.keys(tagsRelation)[0]; if (hasTextValue(primaryTag)) { return primaryTag; } } return void 0; } function buildMarketContentTheme(record, attributeDatas) { const themes = readStringArray( readMarketFieldValue(record, attributeDatas, "content_theme_labels_180d") ); if (themes.length === 0) { return void 0; } if (themes.length <= 2) { return themes.join(" "); } return `${themes.slice(0, 2).join(" ")} ${themes.length - 2}+`; } function readMarketLocation(record, attributeDatas) { return readString(readMarketFieldValue(record, attributeDatas, "city")) ?? void 0; } function readMarketPrice21To60s(record, attributeDatas) { return formatCurrencyValue( readNumericValue(readMarketFieldValue(record, attributeDatas, "price_20_60")) ); } function readMarketRepresentativeVideo(record, attributeDatas) { const items = readArrayLike(readMarketFieldValue(record, attributeDatas, "items")); for (const item of items) { if (!isRecord(item)) { continue; } const title = readString(item.title); if (hasTextValue(title)) { return normalizeExportCellText(title); } } return void 0; } function readMarketGenderLabel(value) { const rawValue = typeof value === "number" ? String(value) : readString(value); if (rawValue === "1") { return "\u7537"; } if (rawValue === "2") { return "\u5973"; } return void 0; } function readBurstRateDisplay(value) { if (value === null) { return void 0; } if (value <= 0) { return "-"; } return formatFractionPercent(value); } function formatCurrencyValue(value) { if (value === null) { return void 0; } return `\xA5${value.toLocaleString("en-US", { maximumFractionDigits: 0 })}`; } function formatWanValue(value) { if (value === null) { return void 0; } return `${formatDecimalWithGrouping(value / 1e4)}w`; } function formatFractionPercent(value) { if (value === null) { return void 0; } return `${formatDecimalDisplay(value * 100)}%`; } function formatDecimalDisplay(value) { if (value === null) { return void 0; } return value.toLocaleString("en-US", { maximumFractionDigits: 1, minimumFractionDigits: 0, useGrouping: false }); } function formatDecimalWithGrouping(value) { return value.toLocaleString("en-US", { maximumFractionDigits: 1, minimumFractionDigits: 0 }); } function readNumericValue(value) { if (typeof value === "number" && Number.isFinite(value)) { return value; } if (typeof value === "string") { const trimmedValue = value.trim(); if (!trimmedValue) { return null; } const parsedValue = Number(trimmedValue); return Number.isFinite(parsedValue) ? parsedValue : null; } return null; } function readStringArray(value) { if (Array.isArray(value)) { return value.filter((item) => typeof item === "string"); } if (typeof value === "string") { try { const parsedValue = JSON.parse(value); return Array.isArray(parsedValue) ? parsedValue.filter((item) => typeof item === "string") : []; } catch { return []; } } return []; } function readArrayLike(value) { if (Array.isArray(value)) { return value; } if (typeof value === "string") { try { const parsedValue = JSON.parse(value); return Array.isArray(parsedValue) ? parsedValue : []; } catch { return []; } } return []; } function readRecordLike(value) { if (isRecord(value)) { return value; } if (typeof value === "string") { try { const parsedValue = JSON.parse(value); return isRecord(parsedValue) ? parsedValue : null; } catch { return null; } } return null; } function readKnownNumber(record, keys) { for (const key of keys) { const value = readNumericValue(record[key]); if (value !== null) { return value; } } return void 0; } function readKnownNumberDeep(value, keys) { if (!isRecord(value)) { return null; } const directValue = readKnownNumber(value, keys); if (typeof directValue === "number") { return directValue; } for (const nestedValue of Object.values(value)) { const candidate = readKnownNumberDeep(unwrapVueRef(nestedValue), keys); if (typeof candidate === "number") { return candidate; } } return null; } // src/content/market/page-bridge.ts var BRIDGE_MARKER = "__SCES_MARKET_PAGE_BRIDGE_INSTALLED__"; var MARKET_SEARCH_REQUEST_PATH = "/gw/api/gsearch/search_for_author_square"; var SERIALIZED_MARKET_ROWS_ATTRIBUTE = "data-sces-market-rows"; installMarketPageBridge(); function installMarketPageBridge() { if (window[BRIDGE_MARKER]) { syncSerializedMarketRows(); return; } window[BRIDGE_MARKER] = true; installMarketRequestSnapshotBridge(); syncSerializedMarketRows(); const observer = new MutationObserver(() => { syncSerializedMarketRows(); }); observer.observe(document.documentElement, { childList: true, subtree: true }); window.setInterval(() => { syncSerializedMarketRows(); }, 1e3); } function installMarketRequestSnapshotBridge() { installFetchSnapshotBridge(); installXmlHttpRequestSnapshotBridge(); } function syncSerializedMarketRows() { if (typeof document === "undefined") { return; } const nextSerializedRows = JSON.stringify(readSerializedMarketRows()); if (document.documentElement.getAttribute(SERIALIZED_MARKET_ROWS_ATTRIBUTE) !== nextSerializedRows) { document.documentElement.setAttribute( SERIALIZED_MARKET_ROWS_ATTRIBUTE, nextSerializedRows ); } } function installFetchSnapshotBridge() { if (typeof window.fetch !== "function") { return; } const originalFetch = window.fetch.bind(window); window.fetch = async (input, init) => { const requestSnapshot = readFetchSnapshot(input, init); const response = await originalFetch(input, init); if (requestSnapshot) { const clonedResponse = response.clone(); void captureMarketSnapshotFromResponse( requestSnapshot, () => clonedResponse.json() ); } return response; }; } function installXmlHttpRequestSnapshotBridge() { const OriginalXmlHttpRequest = window.XMLHttpRequest; if (!OriginalXmlHttpRequest) { return; } const originalOpen = OriginalXmlHttpRequest.prototype.open; const originalSend = OriginalXmlHttpRequest.prototype.send; const originalSetRequestHeader = OriginalXmlHttpRequest.prototype.setRequestHeader; OriginalXmlHttpRequest.prototype.open = function(method, url, ...rest) { this.__scesMarketSnapshot = { headers: {}, method, url: String(url) }; return originalOpen.call(this, method, url, ...rest); }; OriginalXmlHttpRequest.prototype.setRequestHeader = function(name, value) { this.__scesMarketSnapshot?.headers && (this.__scesMarketSnapshot.headers[name] = value); return originalSetRequestHeader.call(this, name, value); }; OriginalXmlHttpRequest.prototype.send = function(body) { const snapshotState = this.__scesMarketSnapshot; if (snapshotState) { snapshotState.body = typeof body === "string" ? body : void 0; this.addEventListener("load", () => { if (this.status < 200 || this.status >= 300 || typeof this.responseText !== "string") { return; } void captureMarketSnapshotFromResponse( snapshotState, async () => JSON.parse(this.responseText) ); }); } return originalSend.call(this, body); }; } async function captureMarketSnapshotFromResponse(snapshot, readPayload) { if (!isMarketSearchRequest(snapshot.url)) { return; } try { const payload = await readPayload(); if (!parseMarketListResponse(payload)) { return; } writeMarketListRequestSnapshot(document, { body: snapshot.body, headers: snapshot.headers, method: snapshot.method, url: snapshot.url }); } catch { } } function readSerializedMarketRows() { const marketList = readMarketList(); return marketList.map((row) => { const attributeDatas = isRecord2(row.attribute_datas) ? row.attribute_datas : {}; const singleVideoAfterSearchRate = readNormalizedFractionRate( attributeDatas.avg_search_after_view_rate_30d ); return { authorId: readString2(row.star_id) ?? readString2(attributeDatas.id) ?? "", authorName: readString2(attributeDatas.nickname) ?? readString2(row.nick_name) ?? "", coreUserId: readString2(attributeDatas.core_user_id) ?? void 0, singleVideoAfterSearchRate }; }).filter((row) => Boolean(row.authorId || row.authorName)); } function readFetchSnapshot(input, init) { const request = input instanceof Request ? input : null; const method = init?.method ?? request?.method ?? "GET"; const url = request?.url ?? String(input); const body = typeof init?.body === "string" ? init.body : typeof request?.bodyUsed === "boolean" && request.bodyUsed ? void 0 : void 0; const headers = serializeHeaders(init?.headers ?? request?.headers); return { body, headers, method, url }; } function serializeHeaders(headers) { if (!headers) { return void 0; } if (headers instanceof Headers) { return Object.fromEntries(headers.entries()); } if (Array.isArray(headers)) { return Object.fromEntries(headers); } return Object.fromEntries( Object.entries(headers).map(([key, value]) => [key, String(value)]) ); } function readMarketList() { if (typeof document === "undefined") { return []; } const marketRoot = document.querySelector(".base-author-list"); const setupState = marketRoot?.__vue__?._setupState; if (!setupState) { return []; } for (const value of Object.values(setupState)) { const candidate = unwrapVueRef2(value); if (Array.isArray(candidate) && looksLikeMarketList(candidate)) { return candidate; } if (!isRecord2(candidate) || !Array.isArray(candidate.marketList)) { continue; } if (looksLikeMarketList(candidate.marketList)) { return candidate.marketList; } } return []; } function isMarketSearchRequest(url) { return url === MARKET_SEARCH_REQUEST_PATH || url.startsWith(`${MARKET_SEARCH_REQUEST_PATH}?`) || url.includes(`${MARKET_SEARCH_REQUEST_PATH}?`) || url.endsWith(MARKET_SEARCH_REQUEST_PATH); } function looksLikeMarketList(value) { const firstRow = value[0]; return isRecord2(firstRow) && ("star_id" in firstRow || "attribute_datas" in firstRow); } function unwrapVueRef2(value) { if (isRecord2(value) && "value" in value) { return value.value; } return value; } function isRecord2(value) { return typeof value === "object" && value !== null; } function readString2(value) { return typeof value === "string" ? value : null; } function readNormalizedFractionRate(value) { return typeof value === "string" ? normalizeFractionRateDisplay(value) ?? void 0 : void 0; } })();