From ab526c234efa9fb97506bd82dbd7ec20c853686d Mon Sep 17 00:00:00 2001 From: wukko Date: Fri, 20 Jun 2025 18:59:35 +0600 Subject: [PATCH] api/loom: add transcription subtitles since there's no language selection (at all), we just add the only transcription if a user wants subtitles --- api/src/processing/match-action.js | 9 +++++- api/src/processing/match.js | 3 +- api/src/processing/services/loom.js | 44 ++++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/api/src/processing/match-action.js b/api/src/processing/match-action.js index a3d9230c..5e77e177 100644 --- a/api/src/processing/match-action.js +++ b/api/src/processing/match-action.js @@ -161,6 +161,14 @@ export default function({ } break; + case "loom": + if (r.subtitles) { + params = { type: "remux" }; + } else { + responseType = "redirect"; + } + break; + case "ok": case "vk": case "tiktok": @@ -174,7 +182,6 @@ export default function({ case "pinterest": case "streamable": case "snapchat": - case "loom": case "twitch": responseType = "redirect"; break; diff --git a/api/src/processing/match.js b/api/src/processing/match.js index f71dd635..220d9593 100644 --- a/api/src/processing/match.js +++ b/api/src/processing/match.js @@ -235,7 +235,8 @@ export default async function({ host, patternMatch, params, isSession, isApiKey case "loom": r = await loom({ - id: patternMatch.id + id: patternMatch.id, + subtitleLang, }); break; diff --git a/api/src/processing/services/loom.js b/api/src/processing/services/loom.js index 749f6e8f..64382108 100644 --- a/api/src/processing/services/loom.js +++ b/api/src/processing/services/loom.js @@ -50,7 +50,42 @@ async function fromRawURL(id) { } } -export default async function({ id }) { +async function getTranscript(id) { + const gql = await fetch(`https://www.loom.com/graphql`, { + method: "POST", + headers: craftHeaders(id), + body: JSON.stringify({ + operationName: "FetchVideoTranscriptForFetchTranscript", + variables: { + videoId: id, + password: null, + }, + query: ` + query FetchVideoTranscriptForFetchTranscript($videoId: ID!, $password: String) { + fetchVideoTranscript(videoId: $videoId, password: $password) { + ... on VideoTranscriptDetails { + captions_source_url + language + __typename + } + ... on GenericError { + message + __typename + } + __typename + } + }`, + }) + }) + .then(r => r.status === 200 && r.json()) + .catch(() => {}); + + if (gql?.data?.fetchVideoTranscript?.captions_source_url?.includes('.vtt?')) { + return gql.data.fetchVideoTranscript.captions_source_url; + } +} + +export default async function({ id, subtitleLang }) { let url = await fromTranscodedURL(id); url ??= await fromRawURL(id); @@ -58,8 +93,15 @@ export default async function({ id }) { return { error: "fetch.empty" } } + let subtitles; + if (subtitleLang) { + const transcript = await getTranscript(id); + if (transcript) subtitles = transcript; + } + return { urls: url, + subtitles, filename: `loom_${id}.mp4`, audioFilename: `loom_${id}_audio` }