api/loom: add support for non-transcoded links, add more tests

This commit is contained in:
jj
2025-05-29 15:29:53 +00:00
parent 8a7b3e9386
commit ff7eb2639d
2 changed files with 76 additions and 22 deletions

View File

@ -1,18 +1,18 @@
import { genericUserAgent } from "../../config.js";
export default async function({ id }) {
const craftHeaders = id => ({
"user-agent": genericUserAgent,
"content-type": "application/json",
origin: "https://www.loom.com",
referer: `https://www.loom.com/share/${id}`,
cookie: `loom_referral_video=${id};`,
"x-loom-request-source": "loom_web_be851af",
});
async function fromTranscodedURL(id) {
const gql = await fetch(`https://www.loom.com/api/campaigns/sessions/${id}/transcoded-url`, {
method: "POST",
headers: {
"user-agent": genericUserAgent,
origin: "https://www.loom.com",
referer: `https://www.loom.com/share/${id}`,
cookie: `loom_referral_video=${id};`,
"apollographql-client-name": "web",
"apollographql-client-version": "14c0b42",
"x-loom-request-source": "loom_web_14c0b42",
},
headers: craftHeaders(id),
body: JSON.stringify({
force_original: false,
password: null,
@ -20,20 +20,47 @@ export default async function({ id }) {
deviceID: null
})
})
.then(r => r.status === 200 ? r.json() : false)
.then(r => r.status === 200 && r.json())
.catch(() => {});
if (!gql) return { error: "fetch.empty" };
if (gql?.url?.includes('.mp4?')) {
return gql.url;
}
}
const videoUrl = gql?.url;
async function fromRawURL(id) {
const gql = await fetch(`https://www.loom.com/api/campaigns/sessions/${id}/raw-url`, {
method: "POST",
headers: craftHeaders(id),
body: JSON.stringify({
anonID: crypto.randomUUID(),
client_name: "web",
client_version: "be851af",
deviceID: null,
force_original: false,
password: null,
supported_mime_types: ["video/mp4"],
})
})
.then(r => r.status === 200 && r.json())
.catch(() => {});
if (videoUrl?.includes('.mp4?')) {
return {
urls: videoUrl,
filename: `loom_${id}.mp4`,
audioFilename: `loom_${id}_audio`
}
if (gql?.url?.includes('.mp4?')) {
return gql.url;
}
}
export default async function({ id }) {
let url = await fromTranscodedURL(id);
url ??= await fromRawURL(id);
if (!url) {
return { error: "fetch.empty" }
}
return { error: "fetch.empty" }
return {
urls: url,
filename: `loom_${id}.mp4`,
audioFilename: `loom_${id}_audio`
}
}

View File

@ -29,5 +29,32 @@
"code": 400,
"status": "error"
}
},
{
"name": "video with no transcodedUrl",
"url": "https://www.loom.com/share/aa3d8b08bee74d05af5b42989e9f33e9",
"params": {},
"expected": {
"code": 200,
"status": "redirect"
}
},
{
"name": "video with title in url",
"url": "https://www.loom.com/share/Meet-AI-workflows-aa3d8b08bee74d05af5b42989e9f33e9",
"params": {},
"expected": {
"code": 200,
"status": "redirect"
}
},
{
"name": "video with title in url (2)",
"url": "https://www.loom.com/share/Unlocking-Incredible-Organizational-Velocity-with-Async-Video-4a2a8baf124c4390954dcbb46a58cfd7",
"params": {},
"expected": {
"code": 200,
"status": "redirect"
}
}
]
]