Skip to content

Commit

Permalink
feat: add pipe for loom (#619)
Browse files Browse the repository at this point in the history
* chore: fix merge frame route and add pipe for loom

* fix: video rendering & file fetching api

---------

Co-authored-by: tribhuwan-kumar <tribhuwankumar725275@gmail.com>
  • Loading branch information
tribhuwan-kumar and tribhuwan-kumar authored Nov 29, 2024
1 parent 6b88b4d commit aaa45d1
Show file tree
Hide file tree
Showing 30 changed files with 7,637 additions and 1 deletion.
3 changes: 3 additions & 0 deletions examples/typescript/pipe-for-loom/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
36 changes: 36 additions & 0 deletions examples/typescript/pipe-for-loom/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
36 changes: 36 additions & 0 deletions examples/typescript/pipe-for-loom/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
59 changes: 59 additions & 0 deletions examples/typescript/pipe-for-loom/app/api/file/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from 'fs';
import path from 'path';
import { NextRequest, NextResponse } from 'next/server';

let isAudio = false;

export async function GET(req: NextRequest) {
const videoPath = req.nextUrl.searchParams.get('path');
if (!videoPath || typeof videoPath !== 'string') {
return NextResponse.json({ error: 'file path is required' }, { status: 400 });
}

try {
const fullPath = path.resolve(videoPath);
console.log(`attempting to access file: ${fullPath}`);

if (fullPath.includes('input') || fullPath.includes('output')){
isAudio = true;
}
const fileStream = fs.createReadStream(fullPath);
const contentType = getContentType(fullPath);

const headers = new Headers();
headers.set('Content-Type', contentType);
headers.set('Accept-Ranges', 'bytes');

return new NextResponse(fileStream, { headers });
} catch (error :any) {
console.error('Error fetching file:', error);
if (error.code === 'ENOENT') {
console.error('Error: File not found');
return NextResponse.json({ error: 'File not found' }, { status: 404 });
} else if (error.code === 'EACCES') {
console.error('Error: Permission denied');
return NextResponse.json({ error: 'Permission denied' }, { status: 403 });
} else {
console.error('Unexpected error:', error);
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
}
}
}

function getContentType(filePath: string): string {
const ext = path.extname(filePath).toLowerCase();
switch (ext) {
case '.mp4':
return 'video/mp4';
case '.webm':
return 'video/webm';
case '.mp3':
return 'audio/mpeg';
case '.wav':
return 'audio/wav';
default:
return isAudio ? "audio/mpeg" : "video/mp4";;
}
}


Binary file added examples/typescript/pipe-for-loom/app/favicon.ico
Binary file not shown.
92 changes: 92 additions & 0 deletions examples/typescript/pipe-for-loom/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;

--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;

--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;

--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;

--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;

--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;

--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;

--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;

--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 10% 3.9%;

--radius: 0.5rem;

--color-1: 0 100% 63%;

--color-2: 270 100% 63%;

--color-3: 210 100% 63%;

--color-4: 195 100% 63%;

--color-5: 90 100% 63%;
}

.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;

--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;

--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;

--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;

--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;

--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;

--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;

--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;

--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
--color-1: 0 100% 63%;
--color-2: 270 100% 63%;
--color-3: 210 100% 63%;
--color-4: 195 100% 63%;
--color-5: 90 100% 63%;
}
}

@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

27 changes: 27 additions & 0 deletions examples/typescript/pipe-for-loom/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Metadata } from "next";
import { Toaster } from "@/components/toaster";
import { Inter } from "next/font/google";
import "./globals.css";

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};

const inter = Inter({ subsets: ["latin"] });

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
{children}

<Toaster />
</body>
</html>
);
}
12 changes: 12 additions & 0 deletions examples/typescript/pipe-for-loom/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client"
import Header from "@/components/header";
import Pipe from "@/components/pipe"

export default function Home() {
return (
<main className="flex flex-col justify-center items-center">
<Header />
<Pipe />
</main>
);
}
81 changes: 81 additions & 0 deletions examples/typescript/pipe-for-loom/components/date-time-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import * as React from "react";
import { format } from "date-fns";
import { Calendar as CalendarIcon } from "lucide-react";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { Input } from "./ui/input";

export function DateTimePicker({
date,
setDate,
className,
}: {
date: Date;
setDate: (date: Date) => void;
className?: string;
}) {
const [selectedDateTime, setSelectedDateTime] = React.useState<Date>(date);

React.useEffect(() => {
setSelectedDateTime(date);
}, [date]);

const handleDateSelect = (selectedDate: Date | undefined) => {
if (selectedDate) {
const newDateTime = new Date(selectedDateTime);
newDateTime.setFullYear(selectedDate.getFullYear());
newDateTime.setMonth(selectedDate.getMonth());
newDateTime.setDate(selectedDate.getDate());
setSelectedDateTime(newDateTime);
setDate(newDateTime);
}
};

const handleTimeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const [hours, minutes] = event.target.value.split(":").map(Number);
if (!isNaN(hours) && !isNaN(minutes)) {
const newDateTime = new Date(selectedDateTime);
newDateTime.setHours(hours);
newDateTime.setMinutes(minutes);
setSelectedDateTime(newDateTime);
setDate(newDateTime);
}
};

return (
<Popover>
<PopoverTrigger asChild>
<Button
variant={"outline"}
className={cn("w-full justify-start text-left font-normal")}
>
<CalendarIcon className="mr-2 h-4 w-4 text-gray-400" size={18} />
{format(date, "PPP HH:mm").toLowerCase()}
</Button>
</PopoverTrigger>
<PopoverContent className={cn("w-auto p-0", className)}>
<Calendar
mode="single"
selected={selectedDateTime}
onSelect={handleDateSelect}
initialFocus
/>
<div className="p-3 border-t border-border">
<Input
type="time"
onChange={handleTimeChange}
value={format(selectedDateTime, "HH:mm")}
/>
</div>
</PopoverContent>
</Popover>
);
}

14 changes: 14 additions & 0 deletions examples/typescript/pipe-for-loom/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"use client"

export default function Header() {
return (
<div className="flex flex-col justify-center items-center mt-6">
<img
className="w-24 h-24"
src="/128x128.png"
alt="screenpipe-logo"
/>
<h1 className="font-bold text-center text-2xl">Screenpipe</h1>
</div>
);
}
Loading

0 comments on commit aaa45d1

Please sign in to comment.