Skip to content

Commit db9c78e

Browse files
committed
Improve Loom download and streaming support
1 parent a23182e commit db9c78e

2 files changed

Lines changed: 358 additions & 68 deletions

File tree

apps/web/actions/loom.ts

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,26 @@ function extractLoomVideoId(url: string): string | null {
5959
async function fetchLoomEndpoint(
6060
videoId: string,
6161
endpoint: string,
62+
includeBody = true,
6263
): Promise<string | null> {
6364
try {
65+
const options: RequestInit = { method: "POST" };
66+
if (includeBody) {
67+
options.headers = {
68+
"Content-Type": "application/json",
69+
Accept: "application/json",
70+
};
71+
options.body = JSON.stringify({
72+
anonID: randomUUID(),
73+
deviceID: null,
74+
force_original: false,
75+
password: null,
76+
});
77+
}
78+
6479
const response = await fetch(
6580
`https://www.loom.com/api/campaigns/sessions/${videoId}/${endpoint}`,
66-
{
67-
method: "POST",
68-
headers: {
69-
"Content-Type": "application/json",
70-
Accept: "application/json",
71-
},
72-
body: JSON.stringify({
73-
anonID: randomUUID(),
74-
deviceID: null,
75-
force_original: false,
76-
password: null,
77-
}),
78-
},
81+
options,
7982
);
8083

8184
if (!response.ok || response.status === 204) {
@@ -131,16 +134,25 @@ function isStreamingUrl(url: string): boolean {
131134
}
132135

133136
async function getLoomDownloadUrl(loomVideoId: string): Promise<string | null> {
134-
const endpoints = ["transcoded-url", "raw-url"] as const;
137+
const requestVariants: Array<{ endpoint: string; includeBody: boolean }> = [
138+
{ endpoint: "transcoded-url", includeBody: true },
139+
{ endpoint: "raw-url", includeBody: true },
140+
{ endpoint: "transcoded-url", includeBody: false },
141+
{ endpoint: "raw-url", includeBody: false },
142+
];
135143

136-
for (const endpoint of endpoints) {
137-
const url = await fetchLoomEndpoint(loomVideoId, endpoint);
144+
let fallbackStreamingUrl: string | null = null;
145+
146+
for (const { endpoint, includeBody } of requestVariants) {
147+
const url = await fetchLoomEndpoint(loomVideoId, endpoint, includeBody);
138148
if (!url) continue;
139149

140150
if (!isStreamingUrl(url)) return url;
151+
152+
if (!fallbackStreamingUrl) fallbackStreamingUrl = url;
141153
}
142154

143-
return null;
155+
return fallbackStreamingUrl;
144156
}
145157

146158
async function fetchLoomOEmbed(
@@ -181,10 +193,9 @@ export async function downloadLoomVideo(
181193
}
182194

183195
try {
184-
const transcodedUrl = await fetchLoomEndpoint(videoId, "transcoded-url");
185-
const rawUrl = await fetchLoomEndpoint(videoId, "raw-url");
196+
const downloadUrl = await getLoomDownloadUrl(videoId);
186197

187-
if (!transcodedUrl && !rawUrl) {
198+
if (!downloadUrl) {
188199
return {
189200
success: false,
190201
error:

0 commit comments

Comments
 (0)