@mux/ai 0.45.0 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-D6VGaoPm.d.ts → index-DAuzEXly.d.ts} +11 -11
- package/dist/{index-BD4acrwt.d.ts → index-DxAt9Jq8.d.ts} +41 -25
- package/dist/index.d.ts +6 -6
- package/dist/index.js +109 -85
- package/dist/index.js.map +1 -1
- package/dist/primitives/index.d.ts +3 -3
- package/dist/primitives/index.js +55 -66
- package/dist/primitives/index.js.map +1 -1
- package/dist/{shots-B7G0IIF1.d.ts → shots-BwpjZDpr.d.ts} +3 -3
- package/dist/workflows/index.d.ts +3 -3
- package/dist/workflows/index.js +102 -78
- package/dist/workflows/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Mux from '@mux/
|
|
1
|
+
import Mux from '@mux/ts';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Workflow Crypto
|
|
@@ -171,7 +171,7 @@ type WorkflowCredentialsInput = WorkflowCredentials | Encrypted<WorkflowCredenti
|
|
|
171
171
|
type ToneType = "neutral" | "playful" | "professional";
|
|
172
172
|
/** Common transport for image-based workflows. */
|
|
173
173
|
type ImageSubmissionMode = "url" | "base64";
|
|
174
|
-
/** Result of calling
|
|
174
|
+
/** Result of calling the Mux SDK asset retrieval helper. */
|
|
175
175
|
type MuxAsset = Awaited<ReturnType<Mux["video"]["assets"]["retrieve"]>>;
|
|
176
176
|
/** Single ready track extracted from a Mux asset. */
|
|
177
177
|
type AssetTextTrack = NonNullable<MuxAsset["tracks"]>[number];
|
|
@@ -294,7 +294,7 @@ interface HotspotOptions {
|
|
|
294
294
|
limit?: number;
|
|
295
295
|
/** Sort order: 'asc' or 'desc' (default: 'desc') */
|
|
296
296
|
orderDirection?: "asc" | "desc";
|
|
297
|
-
/**
|
|
297
|
+
/** @deprecated The API always orders by score; this option is ignored. */
|
|
298
298
|
orderBy?: "score";
|
|
299
299
|
/** Time window for results, e.g., '7:days' (default: '7:days') */
|
|
300
300
|
timeframe?: string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { J as ASK_QUESTIONS_DEFAULT_MAX_ANSWER_OPTION_LENGTH, K as ASK_QUESTIONS_DEFAULT_MAX_FREE_FORM_ANSWER_LENGTH, N as ASK_QUESTIONS_MAX_QUESTIONS_PER_CALL, O as ASK_QUESTIONS_MAX_QUESTION_LENGTH, P as AskQuestionsOptions, Q as AskQuestionsResult, U as AskQuestionsType, V as AudioTranslationOptions, W as AudioTranslationResult, X as AutoCensorProfanityOptions, Y as BurnedInCaptionsAnalysis, Z as BurnedInCaptionsOptions, _ as BurnedInCaptionsPromptOverrides, $ as BurnedInCaptionsPromptSections, a0 as BurnedInCaptionsResult, a1 as CaptionReplacement, a2 as CensorMode, a3 as Chapter, a4 as ChapterSystemPromptSections, a5 as ChaptersOptions, a6 as ChaptersPromptOverrides, a7 as ChaptersPromptSections, a8 as ChaptersResult, a9 as ChaptersType, aa as EditCaptionsOptions, ab as EditCaptionsResult, ac as EmbeddingsOptions, ad as EmbeddingsResult, ae as EngagementInsightsOptions, af as EngagementInsightsResult, ag as GENERATE_TEXT_CALLS_TO_ACTION, ah as GENERATE_TEXT_CHANNELS, ai as GENERATE_TEXT_CHANNEL_CEILINGS, aj as GENERATE_TEXT_FORMATS, ak as GENERATE_TEXT_LENGTH_BOUNDS, al as GENERATE_TEXT_MAX_ARTIFACTS, am as GENERATE_TEXT_MAX_AUDIENCE_CHARS, an as GENERATE_TEXT_MAX_BRAND_TERMS, ao as GENERATE_TEXT_MAX_BRAND_TERMS_TOTAL_CHARS, ap as GENERATE_TEXT_MAX_BRAND_TERM_CHARS, aq as GENERATE_TEXT_MAX_CONCURRENT_GENERATIONS, ar as GENERATE_TEXT_MAX_INSTRUCTIONS_CHARS, as as GENERATE_TEXT_MAX_SHOT_FRAMES, at as GENERATE_TEXT_MAX_VARIANTS, au as GENERATE_TEXT_VOICES, av as GOOGLE_VISION_LIKELIHOOD_TO_SCORE, aw as GenerateTextArtifact, ax as GenerateTextCallToAction, ay as GenerateTextChannel, az as GenerateTextFormat, aA as GenerateTextKeyedItem, aB as GenerateTextLengthLimit, aC as GenerateTextOptions, aD as GenerateTextResult, aE as GenerateTextVariant, aF as GenerateTextVoice, aG as GeneratedTextArtifact, aH as GeneratedTextVariant, aI as HIVE_SEXUAL_CATEGORIES, aJ as HIVE_VIOLENCE_CATEGORIES, aK as HiveModerationOutput, aL as HiveModerationSource, aM as ModerationOptions, aN as ModerationProvider, aO as ModerationResult, aP as MomentInsight, aQ as OverallInsight, aR as ProfanityDetectionPayload, aS as Question, aT as QuestionAnswer, aU as QuestionAnswerType, aV as ReplacementRecord, aW as SpeakerReplacement, aX as StaticRenditionCleanupOutcome, aY as SummarizationOptions, aZ as SummarizationPromptOverrides, a_ as SummarizationPromptSections, a$ as SummaryAndTagsResult, b0 as SummaryType, b1 as ThumbnailModerationScore, b2 as TranslationChunkingOptions, b3 as TranslationOptions, b4 as TranslationPayload, b5 as TranslationResult, b6 as aggregateTokenUsage, b7 as applyOverrideLists, b8 as applyReplacements, b9 as applySpeakerReplacements, ba as askQuestions, bb as buildReplacementRegex, bc as burnedInCaptionsSchema, bd as censorVttContent, be as chapterSchema, bf as chaptersSchema, bg as createReplacer, bh as editCaptions, bi as extractTranscriptSegmentsForHotspots, bj as findGenerateTextLengthViolation, bk as generateChapters, bl as generateEmbeddings, bm as generateEngagementInsights, bn as generateText, bo as generateVideoEmbeddings, bp as getModerationScores, bq as getSummaryAndTags, br as hasBurnedInCaptions, bs as mapShotsToHotspots, bt as measureGenerateTextLength, bu as normalizeTranslatedVtt, bv as profanityDetectionSchema, bw as questionAnswerSchema, bx as resolveGenerateTextLengthLimit, by as resolveGenerateTextLengthLimits, bz as resolveGenerateTextOptions, bA as selectGenerateTextShotFrames, bB as shouldSplitChunkTranslationError, bC as summarySchema, bD as transformCueText, bE as translateAudio, bF as translateCaptions, bG as translationSchema, bH as validateNeverTranslateTerms, bI as verifyNeverTranslateTerms } from '../index-DxAt9Jq8.js';
|
|
2
2
|
export { D as DEFAULT_DESCRIPTION_LENGTH, a as DEFAULT_SUMMARY_KEYWORD_LIMIT, b as DEFAULT_TITLE_LENGTH } from '../summarization-BFmhXeAu.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
import '@ai-sdk/anthropic';
|
|
5
5
|
import '@ai-sdk/google';
|
|
6
6
|
import '@ai-sdk/openai';
|
|
7
|
-
import '../shots-
|
|
8
|
-
import '@mux/
|
|
7
|
+
import '../shots-BwpjZDpr.js';
|
|
8
|
+
import '@mux/ts';
|
package/dist/workflows/index.js
CHANGED
|
@@ -1173,7 +1173,7 @@ function resolveDirectMuxCredentials(record) {
|
|
|
1173
1173
|
function createWorkflowMuxClient(options) {
|
|
1174
1174
|
return {
|
|
1175
1175
|
async createClient() {
|
|
1176
|
-
const { default: MuxClient } = await import("@mux/
|
|
1176
|
+
const { default: MuxClient } = await import("@mux/ts");
|
|
1177
1177
|
return new MuxClient({
|
|
1178
1178
|
tokenId: options.tokenId,
|
|
1179
1179
|
tokenSecret: options.tokenSecret,
|
|
@@ -1913,12 +1913,8 @@ async function getMuxThumbnailBaseUrl(playbackId, credentials) {
|
|
|
1913
1913
|
|
|
1914
1914
|
// src/lib/url-signing.ts
|
|
1915
1915
|
async function createSigningClient(context) {
|
|
1916
|
-
const { default: MuxClient } = await import("@mux/
|
|
1916
|
+
const { default: MuxClient } = await import("@mux/ts");
|
|
1917
1917
|
return new MuxClient({
|
|
1918
|
-
// These are not needed for signing, but the SDK requires them
|
|
1919
|
-
// Using empty strings as we only need the jwt functionality
|
|
1920
|
-
tokenId: env_default.MUX_TOKEN_ID || "",
|
|
1921
|
-
tokenSecret: env_default.MUX_TOKEN_SECRET || "",
|
|
1922
1918
|
jwtSigningKey: context.keyId,
|
|
1923
1919
|
jwtPrivateKey: context.keySecret
|
|
1924
1920
|
});
|
|
@@ -3979,17 +3975,24 @@ function findNameCollisionTextTracks(asset, target) {
|
|
|
3979
3975
|
}
|
|
3980
3976
|
return listTracks(asset, targetType(target)).filter((track) => normalizeTrackName(track.name) === targetName);
|
|
3981
3977
|
}
|
|
3978
|
+
function countTracks(tracks, label, singularVerb, pluralVerb) {
|
|
3979
|
+
const kind = label.toLowerCase();
|
|
3980
|
+
if (tracks.length === 1) {
|
|
3981
|
+
return `${kind === "audio" ? "An" : "A"} ${kind} track ${singularVerb}`;
|
|
3982
|
+
}
|
|
3983
|
+
return `${tracks.length} ${kind} tracks ${pluralVerb}`;
|
|
3984
|
+
}
|
|
3985
|
+
function itOrThem(tracks) {
|
|
3986
|
+
return tracks.length === 1 ? "it" : "them";
|
|
3987
|
+
}
|
|
3982
3988
|
function describeTracks(tracks) {
|
|
3983
3989
|
return tracks.map((track) => `${track.name ?? "(unnamed)"} [${track.language_code ?? "?"}, ${track.type === "audio" ? track.primary ? "primary audio" : "audio" : track.text_source ?? "unknown source"}, ${track.status ?? "ready"}]`).join("; ");
|
|
3984
3990
|
}
|
|
3985
|
-
function planTextTrackReplacement(asset, target, policy
|
|
3991
|
+
function planTextTrackReplacement(asset, target, policy) {
|
|
3986
3992
|
const label = targetType(target) === "audio" ? "Audio" : "Text";
|
|
3987
|
-
const keep = new Set(options.keepTrackIds ?? []);
|
|
3988
3993
|
const conflicts = /* @__PURE__ */ new Map();
|
|
3989
3994
|
for (const track of [...findSameLanguageTextTracks(asset, target), ...findNameCollisionTextTracks(asset, target)]) {
|
|
3990
|
-
|
|
3991
|
-
conflicts.set(track.id, track);
|
|
3992
|
-
}
|
|
3995
|
+
conflicts.set(track.id, track);
|
|
3993
3996
|
}
|
|
3994
3997
|
const conflicting = [...conflicts.values()];
|
|
3995
3998
|
if (conflicting.length === 0) {
|
|
@@ -3998,7 +4001,7 @@ function planTextTrackReplacement(asset, target, policy, options = {}) {
|
|
|
3998
4001
|
if (policy === "fail") {
|
|
3999
4002
|
return {
|
|
4000
4003
|
kind: "blocked",
|
|
4001
|
-
reason: `${label
|
|
4004
|
+
reason: `${countTracks(conflicting, label, "already exists", "already exist")} for language '${target.languageCode}' or name '${target.name}': ${describeTracks(conflicting)}. Set replaceExistingTracks to replace ${itOrThem(conflicting)}.`,
|
|
4002
4005
|
tracks: conflicting.map(summarizeTextTrack)
|
|
4003
4006
|
};
|
|
4004
4007
|
}
|
|
@@ -4015,13 +4018,26 @@ function planTextTrackReplacement(asset, target, policy, options = {}) {
|
|
|
4015
4018
|
if (notGenerated.length > 0) {
|
|
4016
4019
|
return {
|
|
4017
4020
|
kind: "blocked",
|
|
4018
|
-
reason: `${label
|
|
4021
|
+
reason: `${countTracks(notGenerated, label, "that is not Mux-generated exists", "that are not Mux-generated exist")} for language '${target.languageCode}' or name '${target.name}': ${describeTracks(notGenerated)}. Use replaceExistingTracks: "replace_all" to replace ${itOrThem(notGenerated)}.`,
|
|
4019
4022
|
tracks: notGenerated.map(summarizeTextTrack)
|
|
4020
4023
|
};
|
|
4021
4024
|
}
|
|
4022
4025
|
}
|
|
4023
4026
|
return { kind: "replace", toDelete: conflicting.map(summarizeTextTrack) };
|
|
4024
4027
|
}
|
|
4028
|
+
function planSourceTrackReplacement(asset, sourceTrackId, target, policy) {
|
|
4029
|
+
const colliding = findNameCollisionTextTracks(asset, target);
|
|
4030
|
+
const blocking = policy === "fail" ? colliding : colliding.filter((track) => track.id !== sourceTrackId);
|
|
4031
|
+
if (blocking.length > 0) {
|
|
4032
|
+
return {
|
|
4033
|
+
kind: "blocked",
|
|
4034
|
+
reason: `${countTracks(blocking, "Text", "already has", "already have")} the name '${target.name}': ${describeTracks(blocking)}. Choose a different trackName.`,
|
|
4035
|
+
tracks: blocking.map(summarizeTextTrack)
|
|
4036
|
+
};
|
|
4037
|
+
}
|
|
4038
|
+
const source = policy === "replace" ? listTracks(asset, targetType(target)).find((track) => track.id === sourceTrackId) : void 0;
|
|
4039
|
+
return source ? { kind: "replace", toDelete: [summarizeTextTrack(source)] } : { kind: "clear" };
|
|
4040
|
+
}
|
|
4025
4041
|
function isDuplicateTrackNameError(error) {
|
|
4026
4042
|
if (typeof error !== "object" || error === null) {
|
|
4027
4043
|
return false;
|
|
@@ -4077,6 +4093,14 @@ async function createTextTrackOnMux(assetId, languageCode, trackName, presignedU
|
|
|
4077
4093
|
}
|
|
4078
4094
|
async function replaceAndCreateTrack(input) {
|
|
4079
4095
|
"use step";
|
|
4096
|
+
return writeTrack(input, (asset) => planTextTrackReplacement(asset, input.target, input.policy));
|
|
4097
|
+
}
|
|
4098
|
+
async function replaceSourceTrack(input) {
|
|
4099
|
+
"use step";
|
|
4100
|
+
const target = { ...input.target, type: "text" };
|
|
4101
|
+
return writeTrack({ ...input, target }, (asset) => planSourceTrackReplacement(asset, input.sourceTrackId, target, input.policy));
|
|
4102
|
+
}
|
|
4103
|
+
async function writeTrack(input, plan) {
|
|
4080
4104
|
const muxClient = await resolveMuxClient(input.credentials);
|
|
4081
4105
|
const mux = await muxClient.createClient();
|
|
4082
4106
|
const type = targetType(input.target);
|
|
@@ -4096,12 +4120,12 @@ async function replaceAndCreateTrack(input) {
|
|
|
4096
4120
|
}
|
|
4097
4121
|
return failed(error);
|
|
4098
4122
|
}
|
|
4099
|
-
const
|
|
4100
|
-
if (
|
|
4101
|
-
return { ...
|
|
4123
|
+
const planned = plan(asset);
|
|
4124
|
+
if (planned.kind === "blocked") {
|
|
4125
|
+
return { ...planned, deleted };
|
|
4102
4126
|
}
|
|
4103
|
-
if (
|
|
4104
|
-
for (const track of
|
|
4127
|
+
if (planned.kind === "replace") {
|
|
4128
|
+
for (const track of planned.toDelete) {
|
|
4105
4129
|
try {
|
|
4106
4130
|
await mux.video.assets.deleteTrack(input.assetId, track.id);
|
|
4107
4131
|
deleted.push(track);
|
|
@@ -4725,7 +4749,13 @@ async function editCaptionsInternal(assetId, trackId, options, collectedUsage) {
|
|
|
4725
4749
|
{ type: "validation_error" }
|
|
4726
4750
|
);
|
|
4727
4751
|
}
|
|
4728
|
-
|
|
4752
|
+
if (replaceExistingTracksOption !== void 0 && replaceExistingTracksOption !== "replace" && replaceExistingTracksOption !== "fail") {
|
|
4753
|
+
throw new MuxAiError(
|
|
4754
|
+
`replaceExistingTracks must be "replace" or "fail" for editCaptions (received "${String(replaceExistingTracksOption)}").`,
|
|
4755
|
+
{ type: "validation_error" }
|
|
4756
|
+
);
|
|
4757
|
+
}
|
|
4758
|
+
const replaceExistingTracks = replaceExistingTracksOption ?? "replace";
|
|
4729
4759
|
if (!legacyTrackNaming && replaceExistingTracks === "fail" && !providedTrackName) {
|
|
4730
4760
|
throw new MuxAiError(
|
|
4731
4761
|
`trackName is required when replaceExistingTracks is "fail": the edited track cannot reuse the source track's name while the source is kept.`,
|
|
@@ -4781,15 +4811,14 @@ async function editCaptionsInternal(assetId, trackId, options, collectedUsage) {
|
|
|
4781
4811
|
languageCode: sourceLanguageCode,
|
|
4782
4812
|
name: providedTrackName ?? sourceName
|
|
4783
4813
|
};
|
|
4784
|
-
const keepTrackIds = replaceExistingTracks === "fail" ? [trackId] : [];
|
|
4785
4814
|
if (replaceExistingTracks === "fail" && normalizeTrackName(outputTrack.name) === normalizeTrackName(sourceName)) {
|
|
4786
4815
|
throw new MuxAiError(
|
|
4787
|
-
`trackName "${outputTrack.name}" matches the source track's name. Mux track names must be unique; choose a different trackName or use replaceExistingTracks: "
|
|
4816
|
+
`trackName "${outputTrack.name}" matches the source track's name. Mux track names must be unique; choose a different trackName or use replaceExistingTracks: "replace" to replace the source.`,
|
|
4788
4817
|
{ type: "validation_error" }
|
|
4789
4818
|
);
|
|
4790
4819
|
}
|
|
4791
4820
|
if (uploadToMux && !legacyTrackNaming) {
|
|
4792
|
-
const plan =
|
|
4821
|
+
const plan = planSourceTrackReplacement(assetData, trackId, outputTrack, replaceExistingTracks);
|
|
4793
4822
|
if (plan.kind === "blocked") {
|
|
4794
4823
|
throw new MuxAiError(plan.reason, { type: "validation_error" });
|
|
4795
4824
|
}
|
|
@@ -4911,14 +4940,14 @@ async function editCaptionsInternal(assetId, trackId, options, collectedUsage) {
|
|
|
4911
4940
|
} else if (uploadToMux) {
|
|
4912
4941
|
let outcome;
|
|
4913
4942
|
try {
|
|
4914
|
-
outcome = await
|
|
4943
|
+
outcome = await replaceSourceTrack({
|
|
4915
4944
|
assetId,
|
|
4945
|
+
sourceTrackId: trackId,
|
|
4916
4946
|
target: outputTrack,
|
|
4917
4947
|
policy: replaceExistingTracks,
|
|
4918
4948
|
presignedUrl,
|
|
4919
4949
|
closedCaptions: sourceTrack.closed_captions,
|
|
4920
4950
|
passthrough: trackPassthrough,
|
|
4921
|
-
keepTrackIds,
|
|
4922
4951
|
credentials
|
|
4923
4952
|
});
|
|
4924
4953
|
} catch (error) {
|
|
@@ -5389,25 +5418,22 @@ async function getHeatmapForAsset(assetId, options = {}) {
|
|
|
5389
5418
|
"use step";
|
|
5390
5419
|
return fetchHeatmap("assets", assetId, options);
|
|
5391
5420
|
}
|
|
5392
|
-
function transformHeatmapResponse(response) {
|
|
5393
|
-
return {
|
|
5394
|
-
assetId: response.data.asset_id,
|
|
5395
|
-
videoId: response.data.video_id,
|
|
5396
|
-
playbackId: response.data.playback_id,
|
|
5397
|
-
heatmap: response.data.heatmap,
|
|
5398
|
-
timeframe: response.timeframe
|
|
5399
|
-
};
|
|
5400
|
-
}
|
|
5401
5421
|
async function fetchHeatmap(identifierType, id, options) {
|
|
5402
5422
|
"use step";
|
|
5403
5423
|
const { timeframe = "7:days", credentials } = options;
|
|
5404
5424
|
const muxClient = await getMuxClientFromEnv(credentials);
|
|
5405
5425
|
const mux = await muxClient.createClient();
|
|
5406
|
-
const
|
|
5407
|
-
|
|
5408
|
-
const
|
|
5409
|
-
const
|
|
5410
|
-
return
|
|
5426
|
+
const query = { timeframe: [timeframe] };
|
|
5427
|
+
const resource = identifierType === "playback-ids" ? mux.data.engagement.playbackIds : mux.data.engagement[identifierType];
|
|
5428
|
+
const response = await resource.heatmap(id, query);
|
|
5429
|
+
const { data } = response;
|
|
5430
|
+
return {
|
|
5431
|
+
assetId: data.asset_id ?? (identifierType === "assets" ? id : void 0),
|
|
5432
|
+
videoId: data.video_id ?? (identifierType === "videos" ? id : void 0),
|
|
5433
|
+
playbackId: data.playback_id ?? (identifierType === "playback-ids" ? id : void 0),
|
|
5434
|
+
heatmap: data.heatmap,
|
|
5435
|
+
timeframe: response.timeframe
|
|
5436
|
+
};
|
|
5411
5437
|
}
|
|
5412
5438
|
|
|
5413
5439
|
// src/primitives/hotspots.ts
|
|
@@ -5416,43 +5442,37 @@ async function getHotspotsForAsset(assetId, options = {}) {
|
|
|
5416
5442
|
const response = await fetchHotspots("assets", assetId, options);
|
|
5417
5443
|
return response.hotspots;
|
|
5418
5444
|
}
|
|
5419
|
-
function transformHotspotResponse(response) {
|
|
5420
|
-
return {
|
|
5421
|
-
assetId: response.data.asset_id,
|
|
5422
|
-
videoId: response.data.video_id,
|
|
5423
|
-
playbackId: response.data.playback_id,
|
|
5424
|
-
hotspots: response.data.hotspots.map((h) => ({
|
|
5425
|
-
startMs: h.start_ms,
|
|
5426
|
-
endMs: h.end_ms,
|
|
5427
|
-
score: h.score
|
|
5428
|
-
}))
|
|
5429
|
-
};
|
|
5430
|
-
}
|
|
5431
5445
|
async function fetchHotspots(identifierType, id, options) {
|
|
5432
5446
|
"use step";
|
|
5433
5447
|
const {
|
|
5434
5448
|
limit = 5,
|
|
5435
5449
|
orderDirection = "desc",
|
|
5436
|
-
orderBy = "score",
|
|
5437
5450
|
timeframe = "7:days",
|
|
5438
5451
|
credentials
|
|
5439
5452
|
} = options;
|
|
5440
5453
|
const muxClient = await getMuxClientFromEnv(credentials);
|
|
5441
5454
|
const mux = await muxClient.createClient();
|
|
5442
|
-
const
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
const
|
|
5448
|
-
const response = await
|
|
5449
|
-
|
|
5455
|
+
const query = {
|
|
5456
|
+
limit,
|
|
5457
|
+
order_direction: orderDirection,
|
|
5458
|
+
timeframe: [timeframe]
|
|
5459
|
+
};
|
|
5460
|
+
const resource = identifierType === "playback-ids" ? mux.data.engagement.playbackIds : mux.data.engagement[identifierType];
|
|
5461
|
+
const response = await resource.hotspots(id, query);
|
|
5462
|
+
const { data } = response;
|
|
5463
|
+
return {
|
|
5464
|
+
assetId: data.asset_id ?? (identifierType === "assets" ? id : void 0),
|
|
5465
|
+
videoId: data.video_id ?? (identifierType === "videos" ? id : void 0),
|
|
5466
|
+
playbackId: data.playback_id ?? (identifierType === "playback-ids" ? id : void 0),
|
|
5467
|
+
hotspots: data.hotspots.map((h) => ({
|
|
5468
|
+
startMs: h.start_ms,
|
|
5469
|
+
endMs: h.end_ms,
|
|
5470
|
+
score: h.score
|
|
5471
|
+
}))
|
|
5472
|
+
};
|
|
5450
5473
|
}
|
|
5451
5474
|
|
|
5452
5475
|
// src/primitives/shots.ts
|
|
5453
|
-
function getShotsPath(assetId) {
|
|
5454
|
-
return `/video/v1/assets/${assetId}/shots`;
|
|
5455
|
-
}
|
|
5456
5476
|
function mapManifestShots(shots) {
|
|
5457
5477
|
let usedDeprecatedField = false;
|
|
5458
5478
|
const mapped = shots.map((shot, index) => {
|
|
@@ -5492,29 +5512,35 @@ async function fetchShotsFromManifest(shotsManifestUrl) {
|
|
|
5492
5512
|
}
|
|
5493
5513
|
return mapManifestShots(manifest.shots);
|
|
5494
5514
|
}
|
|
5495
|
-
async function transformShotsResponse(
|
|
5496
|
-
switch (
|
|
5515
|
+
async function transformShotsResponse(data) {
|
|
5516
|
+
switch (data.status) {
|
|
5497
5517
|
case "pending":
|
|
5498
5518
|
return {
|
|
5499
5519
|
status: "pending",
|
|
5500
|
-
createdAt:
|
|
5520
|
+
createdAt: data.created_at
|
|
5501
5521
|
};
|
|
5502
|
-
case "errored":
|
|
5522
|
+
case "errored": {
|
|
5523
|
+
const details = data.errors ?? data.error;
|
|
5503
5524
|
return {
|
|
5504
5525
|
status: "errored",
|
|
5505
|
-
createdAt:
|
|
5506
|
-
error:
|
|
5526
|
+
createdAt: data.created_at,
|
|
5527
|
+
error: {
|
|
5528
|
+
type: details?.type ?? "unknown",
|
|
5529
|
+
messages: details?.messages ?? []
|
|
5530
|
+
}
|
|
5507
5531
|
};
|
|
5532
|
+
}
|
|
5508
5533
|
case "completed":
|
|
5534
|
+
if (!data.shots_manifest_url) {
|
|
5535
|
+
throw new Error("Completed shots response is missing shots_manifest_url");
|
|
5536
|
+
}
|
|
5509
5537
|
return {
|
|
5510
5538
|
status: "completed",
|
|
5511
|
-
createdAt:
|
|
5512
|
-
shots: await fetchShotsFromManifest(
|
|
5539
|
+
createdAt: data.created_at,
|
|
5540
|
+
shots: await fetchShotsFromManifest(data.shots_manifest_url)
|
|
5513
5541
|
};
|
|
5514
|
-
default:
|
|
5515
|
-
|
|
5516
|
-
throw new Error(`Unsupported shots response: ${JSON.stringify(exhaustiveCheck)}`);
|
|
5517
|
-
}
|
|
5542
|
+
default:
|
|
5543
|
+
throw new Error(`Unsupported shots status '${data.status}'`);
|
|
5518
5544
|
}
|
|
5519
5545
|
}
|
|
5520
5546
|
async function getShotsForAsset(assetId, options = {}) {
|
|
@@ -5522,10 +5548,8 @@ async function getShotsForAsset(assetId, options = {}) {
|
|
|
5522
5548
|
const { credentials } = options;
|
|
5523
5549
|
const muxClient = await getMuxClientFromEnv(credentials);
|
|
5524
5550
|
const mux = await muxClient.createClient();
|
|
5525
|
-
const
|
|
5526
|
-
|
|
5527
|
-
);
|
|
5528
|
-
return await transformShotsResponse(response);
|
|
5551
|
+
const data = await mux.video.assets.retrieveShots(assetId);
|
|
5552
|
+
return await transformShotsResponse(data);
|
|
5529
5553
|
}
|
|
5530
5554
|
|
|
5531
5555
|
// src/workflows/engagement-insights.ts
|