Skip to content

Commit

Permalink
feat: Tidy up S3 config stuff (e.g. use v.cap.so still if not custom …
Browse files Browse the repository at this point in the history
…bucket)
  • Loading branch information
richiemcilroy committed Nov 22, 2024
1 parent d58c7d7 commit 4aca804
Show file tree
Hide file tree
Showing 14 changed files with 291 additions and 151 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@ CAP_DESKTOP_SENTRY_URL=https://efd3156d9c0a8a49bee3ee675bec80d8@o450685977152716

# Google OAuth
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
3 changes: 1 addition & 2 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1536,12 +1536,11 @@ async fn delete_auth_open_signin(app: AppHandle) -> Result<(), String> {
if let Some(window) = CapWindowId::Camera.get(&app) {
window.close().ok();
}

if let Some(window) = CapWindowId::Main.get(&app) {
window.close().ok();
}

while CapWindowId::Main.get(&app).is_some() {
while CapWindowId::Main.get(&app).is_none() {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
}

Expand Down
10 changes: 5 additions & 5 deletions apps/desktop/src-tauri/src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,12 +414,12 @@ fn position_traffic_lights_impl(
let c_win = window.clone();
window
.run_on_main_thread(move || {
let ns_window = match c_win.ns_window() {
Ok(handle) => handle,
Err(_) => return,
};
position_window_controls(
UnsafeWindowHandle(
c_win
.ns_window()
.expect("Failed to get native window handle"),
),
UnsafeWindowHandle(ns_window),
&controls_inset.unwrap_or(DEFAULT_TRAFFIC_LIGHTS_INSET),
);
})
Expand Down
20 changes: 19 additions & 1 deletion apps/desktop/src/routes/(window-chrome)/(main).tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ export default function () {
},
}));

const [isUpgraded] = createResource(() => commands.checkUpgradedAndUpdate());

createAsync(() => getAuth());

createUpdateCheck();
Expand Down Expand Up @@ -118,7 +120,23 @@ export default function () {
return (
<div class="flex justify-center flex-col p-[1rem] gap-[0.75rem] text-[0.875rem] font-[400] bg-gray-50 h-full">
<div class="flex items-center justify-between pb-[0.25rem]">
<IconCapLogoFull class="w-[90px] h-auto" />
<div class="flex items-center space-x-1">
<IconCapLogoFull class="w-[90px] h-auto" />
<span
onClick={async () => {
if (!isUpgraded()) {
await commands.showWindow("Upgrade");
}
}}
class={`text-[0.625rem] ${
isUpgraded()
? "bg-blue-400 text-gray-50"
: "bg-gray-200 text-gray-400 cursor-pointer hover:bg-gray-300"
} rounded-lg px-1.5 py-0.5`}
>
{isUpgraded() ? "Pro" : "Free"}
</span>
</div>
<div class="flex items-center space-x-2">
<Tooltip.Root openDelay={0}>
<Tooltip.Trigger>
Expand Down
27 changes: 18 additions & 9 deletions apps/embed/app/view/[videoId]/_components/ShareVideo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,29 +83,38 @@ export const ShareVideo = ({

useEffect(() => {
if (videoMetadataLoaded) {
console.log("Metadata loaded");
setIsLoading(false);
}
}, [videoMetadataLoaded]);

useEffect(() => {
const onVideoLoadedMetadata = () => {
console.log("Video metadata loaded");
setVideoMetadataLoaded(true);
if (videoRef.current) {
setLongestDuration(videoRef.current.duration);
setVideoMetadataLoaded(true);
setIsLoading(false);
}
};

const videoElement = videoRef.current;
const onCanPlay = () => {
setVideoMetadataLoaded(true);
setIsLoading(false);
};

videoElement?.addEventListener("loadedmetadata", onVideoLoadedMetadata);
const videoElement = videoRef.current;
if (videoElement) {
videoElement.addEventListener("loadedmetadata", onVideoLoadedMetadata);
videoElement.addEventListener("canplay", onCanPlay);
}

return () => {
videoElement?.removeEventListener(
"loadedmetadata",
onVideoLoadedMetadata
);
if (videoElement) {
videoElement.removeEventListener(
"loadedmetadata",
onVideoLoadedMetadata
);
videoElement.removeEventListener("canplay", onCanPlay);
}
};
}, []);

Expand Down
20 changes: 1 addition & 19 deletions apps/embed/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,7 @@ const nextConfig = {
remotePatterns: [
{
protocol: "https",
hostname: "*.amazonaws.com",
port: "",
pathname: "**",
},
{
protocol: "https",
hostname: "*.cloudfront.net",
port: "",
pathname: "**",
},
{
protocol: "https",
hostname: "*v.cap.so",
port: "",
pathname: "**",
},
{
protocol: "https",
hostname: "*tasks.cap.so",
hostname: "**",
port: "",
pathname: "**",
},
Expand Down
32 changes: 31 additions & 1 deletion apps/web/app/api/playlist/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,37 @@ export async function GET(request: NextRequest) {
}
}

if (!bucket || video.awsBucket === process.env.NEXT_PUBLIC_CAP_AWS_BUCKET) {
if (video.source.type === "desktopMP4") {
return new Response(null, {
status: 302,
headers: {
...getHeaders(origin),
Location: `https://v.cap.so/${userId}/${videoId}/result.mp4`,
},
});
}

if (video.source.type === "MediaConvert") {
return new Response(null, {
status: 302,
headers: {
...getHeaders(origin),
Location: `https://v.cap.so/${userId}/${videoId}/output/video_recording_000.m3u8`,
},
});
}

const playlistUrl = `https://v.cap.so/${userId}/${videoId}/combined-source/stream.m3u8`;
return new Response(null, {
status: 302,
headers: {
...getHeaders(origin),
Location: playlistUrl,
},
});
}

const Bucket = getS3Bucket(bucket);
const videoPrefix = `${userId}/${videoId}/video/`;
const audioPrefix = `${userId}/${videoId}/audio/`;
Expand Down Expand Up @@ -129,7 +160,6 @@ export async function GET(request: NextRequest) {
{ expiresIn: 3600 }
);

console.log({ playlistUrl });
return new Response(null, {
status: 302,
headers: {
Expand Down
30 changes: 26 additions & 4 deletions apps/web/app/api/screenshot/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { type NextRequest } from "next/server";
import { db } from "@cap/database";
import { s3Buckets, videos } from "@cap/database/schema";
import { eq } from "drizzle-orm";
import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3";
import { S3Client, ListObjectsV2Command, GetObjectCommand } from "@aws-sdk/client-s3";
import { getCurrentUser } from "@cap/database/auth/session";
import { getHeaders } from "@/utils/helpers";
import { createS3Client, getS3Bucket } from "@/utils/s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

export const revalidate = 3599;
export const revalidate = 0;

export async function OPTIONS(request: NextRequest) {
const origin = request.headers.get("origin") as string;
Expand Down Expand Up @@ -47,7 +48,15 @@ export async function GET(request: NextRequest) {
);
}

const { video, bucket } = query[0];
const result = query[0];
if (!result?.video || !result?.bucket) {
return new Response(
JSON.stringify({ error: true, message: "Video or bucket not found" }),
{ status: 401, headers: getHeaders(origin) }
);
}

const { video, bucket } = result;

if (video.public === false) {
const user = await getCurrentUser();
Expand Down Expand Up @@ -85,7 +94,20 @@ export async function GET(request: NextRequest) {
);
}

const screenshotUrl = `https://v.cap.so/${screenshot.Key}`;
let screenshotUrl: string;

if (video.awsBucket !== process.env.NEXT_PUBLIC_CAP_AWS_BUCKET) {
screenshotUrl = await getSignedUrl(
s3Client,
new GetObjectCommand({
Bucket,
Key: screenshot.Key
}),
{ expiresIn: 3600 }
);
} else {
screenshotUrl = `https://v.cap.so/${screenshot.Key}`;
}

return new Response(JSON.stringify({ url: screenshotUrl }), {
status: 200,
Expand Down
68 changes: 54 additions & 14 deletions apps/web/app/api/thumbnail/route.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { NextRequest } from "next/server";
import { ListObjectsV2Command } from "@aws-sdk/client-s3";
import { ListObjectsV2Command, GetObjectCommand } from "@aws-sdk/client-s3";
import { getHeaders } from "@/utils/helpers";
import { db } from "@cap/database";
import { eq } from "drizzle-orm";
import { s3Buckets, videos } from "@cap/database/schema";
import { createS3Client, getS3Bucket } from "@/utils/s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

export const revalidate = 3500;
export const revalidate = 0;

export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl;
Expand Down Expand Up @@ -46,12 +47,33 @@ export async function GET(request: NextRequest) {
);
}

const { video, bucket } = query[0];
const Bucket = getS3Bucket(bucket);
const result = query[0];
if (!result?.video) {
return new Response(
JSON.stringify({ error: true, message: "Video not found" }),
{
status: 401,
headers: getHeaders(origin),
}
);
}

const s3Client = createS3Client(bucket);
const { video } = result;
const prefix = `${userId}/${videoId}/`;

let thumbnailUrl: string;

if (!result.bucket || video.awsBucket === process.env.NEXT_PUBLIC_CAP_AWS_BUCKET) {
thumbnailUrl = `https://v.cap.so/${prefix}screenshot/screen-capture.jpg`;
return new Response(JSON.stringify({ screen: thumbnailUrl }), {
status: 200,
headers: getHeaders(origin),
});
}

const Bucket = getS3Bucket(result.bucket);
const s3Client = createS3Client(result.bucket);

try {
const listCommand = new ListObjectsV2Command({
Bucket,
Expand All @@ -61,29 +83,47 @@ export async function GET(request: NextRequest) {
const listResponse = await s3Client.send(listCommand);
const contents = listResponse.Contents || [];

let thumbnailKey = contents.find((item) => item.Key?.endsWith(".png"))?.Key;
const thumbnailKey = contents.find((item) =>
item.Key?.endsWith("screen-capture.jpg")
)?.Key;

if (!thumbnailKey) {
thumbnailKey = `${prefix}screenshot/screen-capture.jpg`;
return new Response(
JSON.stringify({
error: true,
message: "No thumbnail found for this video",
}),
{
status: 404,
headers: getHeaders(origin),
}
);
}

const thumbnailUrl = `https://v.cap.so/${thumbnailKey}`;

return new Response(JSON.stringify({ screen: thumbnailUrl }), {
status: 200,
headers: getHeaders(origin),
});
thumbnailUrl = await getSignedUrl(
s3Client,
new GetObjectCommand({
Bucket,
Key: thumbnailKey
}),
{ expiresIn: 3600 }
);
} catch (error) {
console.error("Error generating thumbnail URL:", error);
return new Response(
JSON.stringify({
error: true,
message: "Error generating thumbnail URL",
details: error instanceof Error ? error.message : "Unknown error",
}),
{
status: 500,
headers: getHeaders(origin),
}
);
}

return new Response(JSON.stringify({ screen: thumbnailUrl }), {
status: 200,
headers: getHeaders(origin),
});
}
Loading

0 comments on commit 4aca804

Please sign in to comment.