Populating metadata

This commit is contained in:
2026-08-05 22:29:38 -05:00
parent cd1bb5460d
commit 235f76a124
7 changed files with 508 additions and 35 deletions

View File

@@ -6,6 +6,7 @@ const SPLICE_DOMAIN_RE = /^https?:\/\/([a-z0-9-]+\.)*splice\.com(\/|$)/i;
const GRAPHQL_URL_FRAGMENT = "surfaces-graphql.splice.com/graphql";
const PROBE_EVENT_SOURCE = "S3_CAPTURE_PROBE";
const DEBUG_CAPTURE = true;
const DEBUG_PLAYBACK_META_MARKER = "S3DBG_PLAYBAR_META_V2";
let knownUrls = new Set();
let knownPerformanceUrls = new Set();
let observer = null;
@@ -14,6 +15,13 @@ let performanceObserver = null;
let fetchPatched = false;
let xhrPatched = false;
let probeListenerInstalled = false;
let currentPlaybackFilename = "";
let currentPlaybackKey = "";
let currentPlaybackBpm = "";
let currentPlaybackTags = [];
let currentPlaybackCoverImageUrl = "";
let lastPlaybackMetaSignature = "";
let lastPlaybackMetaApplied = false;
function isDomainAllowed(url) {
return typeof url === "string" && SPLICE_DOMAIN_RE.test(url);
@@ -55,6 +63,121 @@ function normalizeUrl(rawUrl) {
}
}
function normalizeFileName(raw) {
if (typeof raw !== "string") {
return "";
}
const trimmed = raw.trim();
if (!trimmed) {
return "";
}
const parts = trimmed.split("/");
return parts[parts.length - 1] || trimmed;
}
function getPlaybackRoot() {
const playbar = document.querySelector(TARGET_SELECTOR);
if (playbar) {
return playbar;
}
const filenameNode = document.querySelector('[data-qa="filename"]');
if (filenameNode && typeof filenameNode.closest === "function") {
return filenameNode.closest(".playbar-playback-info-bar");
}
return null;
}
function queryPlaybackNode(selector) {
const root = getPlaybackRoot();
if (!root) {
return null;
}
return root.querySelector(selector);
}
function getPlaybackFilenameFromDom() {
const el = queryPlaybackNode('[data-qa="filename"]');
if (!el) {
return "";
}
return normalizeFileName(el.textContent || "");
}
function getPlaybackKeyFromDom() {
const el = queryPlaybackNode('[data-qa="key"]');
return el ? String(el.textContent || "").trim() : "";
}
function getPlaybackBpmFromDom() {
const el = queryPlaybackNode('[data-qa="bpm"]');
return el ? String(el.textContent || "").trim() : "";
}
function getPlaybackTagsFromDom() {
const root = queryPlaybackNode('[data-qa="tags"]');
if (!root) {
return [];
}
const tags = [];
const spans = root.querySelectorAll("span.tag");
for (const span of spans) {
const value = String(span.textContent || "").trim();
if (value) {
tags.push(value);
}
}
return Array.from(new Set(tags));
}
function getPlaybackCoverImageFromDom() {
const img = queryPlaybackNode('[data-qa="cover-art-image"]');
if (!img) {
return "";
}
const src = img.getAttribute("src") || img.currentSrc || "";
return normalizeUrl(src);
}
function extractCoverImageFromGraphqlItem(item) {
if (!item || typeof item !== "object") {
return "";
}
const ownFiles = Array.isArray(item.files) ? item.files : [];
for (const file of ownFiles) {
if (!file || typeof file !== "object") {
continue;
}
const typeSlug = String(file.asset_file_type_slug || "").toLowerCase();
if (typeSlug !== "cover_image") {
continue;
}
const url = normalizeUrl(file.url || "");
if (url) {
return url;
}
}
if (!item.parents || !Array.isArray(item.parents.items)) {
return "";
}
for (const parent of item.parents.items) {
const files = parent && Array.isArray(parent.files) ? parent.files : [];
for (const file of files) {
if (!file || typeof file !== "object") {
continue;
}
const typeSlug = String(file.asset_file_type_slug || "").toLowerCase();
if (typeSlug !== "cover_image") {
continue;
}
const url = normalizeUrl(file.url || "");
if (url) {
return url;
}
}
}
return "";
}
function logDebug(message, extra) {
if (!DEBUG_CAPTURE) {
return;
@@ -142,6 +265,13 @@ function extractPreviewContextsFromGraphql(json) {
continue;
}
const sampleId = typeof item.uuid === "string" ? item.uuid.toLowerCase() : "";
const itemName = normalizeFileName(String(item.name || ""));
const itemKey = typeof item.key === "string" ? item.key.trim().toUpperCase() : "";
const itemBpm = item.bpm == null ? "" : String(item.bpm).trim();
const itemTags = Array.isArray(item.tags)
? Array.from(new Set(item.tags.map((tag) => (tag && tag.label ? String(tag.label).trim() : "")).filter(Boolean)))
: [];
const itemCoverImageUrl = extractCoverImageFromGraphqlItem(item);
const files = Array.isArray(item.files) ? item.files : [];
for (const file of files) {
@@ -155,7 +285,12 @@ function extractPreviewContextsFromGraphql(json) {
}
contexts.push({
sampleId: sampleId || extractSampleIdFromUrl(fileUrl),
previewUrl: fileUrl
previewUrl: fileUrl,
fileName: itemName,
key: itemKey,
bpm: itemBpm,
tags: itemTags,
coverImageUrl: itemCoverImageUrl
});
}
}
@@ -221,7 +356,8 @@ function captureUrls(inputUrls) {
browser.runtime.sendMessage({
type: "CAPTURE_URLS",
urls: newUrls,
source: "content_capture"
source: "content_capture",
fileName: getPlaybackFilenameFromDom()
}).catch(() => {
// Ignore transient extension context failures.
});
@@ -499,6 +635,7 @@ function startUiObserver() {
}
observer = new MutationObserver(() => {
injectControls();
syncPlaybackMeta();
});
observer.observe(document.documentElement, { childList: true, subtree: true });
}
@@ -527,6 +664,71 @@ function startCaptureObserver() {
});
}
function syncPlaybackMeta() {
const fileName = getPlaybackFilenameFromDom();
const key = getPlaybackKeyFromDom();
const bpm = getPlaybackBpmFromDom();
const tags = getPlaybackTagsFromDom();
const coverImageUrl = getPlaybackCoverImageFromDom();
const sameTags =
tags.length === currentPlaybackTags.length &&
tags.every((tag, idx) => tag === currentPlaybackTags[idx]);
if (
(!fileName || fileName === currentPlaybackFilename) &&
key === currentPlaybackKey &&
bpm === currentPlaybackBpm &&
sameTags &&
coverImageUrl === currentPlaybackCoverImageUrl
) {
const signature = JSON.stringify({
fileName: currentPlaybackFilename,
key: currentPlaybackKey,
bpm: currentPlaybackBpm,
tags: currentPlaybackTags,
coverImageUrl: currentPlaybackCoverImageUrl
});
if (lastPlaybackMetaApplied && signature === lastPlaybackMetaSignature) {
return;
}
}
if (fileName) {
currentPlaybackFilename = fileName;
}
currentPlaybackKey = key;
currentPlaybackBpm = bpm;
currentPlaybackTags = tags;
currentPlaybackCoverImageUrl = coverImageUrl;
const payload = {
type: "UPDATE_ACTIVE_PLAYBACK_META",
fileName: currentPlaybackFilename,
key: currentPlaybackKey,
bpm: currentPlaybackBpm,
tags: currentPlaybackTags,
coverImageUrl: currentPlaybackCoverImageUrl
};
if (DEBUG_CAPTURE) {
console.debug(DEBUG_PLAYBACK_META_MARKER, {
fileName: payload.fileName,
key: payload.key,
bpm: payload.bpm,
tagsCount: Array.isArray(payload.tags) ? payload.tags.length : 0,
coverImageUrl: payload.coverImageUrl
});
}
const signature = JSON.stringify(payload);
lastPlaybackMetaSignature = signature;
lastPlaybackMetaApplied = false;
browser.runtime.sendMessage(payload).then((result) => {
// Keep retrying on the next interval until background confirms attachment.
lastPlaybackMetaApplied = Boolean(result && result.ok);
}).catch(() => {
lastPlaybackMetaApplied = false;
// Ignore transient extension messaging failures.
});
}
function installPageProbeListener() {
if (probeListenerInstalled) {
return;
@@ -584,15 +786,21 @@ function init() {
installPageProbeListener();
injectPageProbeScript();
currentPlaybackFilename = getPlaybackFilenameFromDom();
currentPlaybackKey = getPlaybackKeyFromDom();
currentPlaybackBpm = getPlaybackBpmFromDom();
currentPlaybackTags = getPlaybackTagsFromDom();
currentPlaybackCoverImageUrl = getPlaybackCoverImageFromDom();
lastPlaybackMetaSignature = "";
lastPlaybackMetaApplied = false;
scanNodeForUrls(document);
patchFetch();
patchXhr();
capturePerformanceResourceUrls();
startPerformanceObserver();
window.setInterval(capturePerformanceResourceUrls, 2000);
// Avoid buffered resource sweeps; they can re-capture stale previews.
injectControls();
startUiObserver();
startCaptureObserver();
window.setInterval(syncPlaybackMeta, 700);
}
init();