├── .env.sample ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── app ├── about │ └── page.tsx ├── admin │ ├── adminpage.tsx │ ├── page.tsx │ └── videolist │ │ ├── addtogallery.tsx │ │ ├── page.tsx │ │ └── vidlist.tsx ├── api │ ├── addtogallery │ │ └── route.ts │ ├── addtowaitlist │ │ └── route.ts │ ├── aigetwebcontent │ │ └── route.ts │ ├── aiimgtovid │ │ └── route.ts │ ├── aiurltovideo │ │ ├── baseaivideo.ts │ │ └── route.ts │ ├── auth │ │ └── [...nextauth] │ │ │ └── route.ts │ ├── createitem │ │ └── route.ts │ ├── createvideo │ │ ├── route.ts │ │ └── samples.ts │ ├── createvideorequest │ │ └── route.ts │ ├── getcount │ │ └── route.ts │ ├── getlambdastatus │ │ └── route.ts │ ├── getusercredits │ │ └── route.ts │ ├── getvideorequestbyid │ │ └── route.ts │ ├── grant_credits │ │ └── route.ts │ ├── pexels │ │ └── route.ts │ ├── processqueue │ │ └── route.ts │ ├── saveonly │ │ └── route.ts │ ├── stripe │ │ ├── checkout_sessions │ │ │ └── route.ts │ │ ├── get_prices │ │ │ └── route.ts │ │ └── webhooks │ │ │ └── route.ts │ ├── tts │ │ ├── oaitts.ts │ │ ├── route.ts │ │ └── tts.ts │ └── use_credits │ │ └── route.ts ├── blog │ └── page.tsx ├── buycredits │ ├── OfferList.tsx │ ├── PricingBox.tsx │ ├── displayproducts.tsx │ └── page.tsx ├── checkout │ ├── checkout.tsx │ └── page.tsx ├── contact │ └── page.tsx ├── create-video-ai-url │ ├── createvideourl.tsx │ └── page.tsx ├── create-video-api │ ├── example.tsx │ └── page.tsx ├── create-video-json │ ├── datavidintro.tsx │ ├── editor.tsx │ ├── jsonedit.tsx │ └── page.tsx ├── create-video │ ├── choosestock.tsx │ ├── createvideo2.tsx │ ├── defaults.ts │ ├── page.tsx │ └── temp.tsx ├── data-to-video-how │ └── page.tsx ├── error │ └── page.tsx ├── faq │ └── page.tsx ├── gallery │ ├── displaygallery.tsx │ └── page.tsx ├── getstarted │ ├── getstarted.tsx │ └── page.tsx ├── global-error.tsx ├── head.tsx ├── layout.tsx ├── my-account │ ├── myaccount.tsx │ └── page.tsx ├── not-found.tsx ├── page.tsx ├── privacy │ └── page.tsx ├── providers.tsx ├── return │ └── page.tsx ├── roadmap │ └── page.tsx ├── signin │ ├── emailsignin.tsx │ ├── page.tsx │ └── providerbuttons.tsx ├── sitemap.ts ├── styles │ └── index.css ├── terms │ └── page.tsx ├── use-cases │ ├── ai-url-to-video │ │ └── page.tsx │ ├── automate-videos-apis │ │ └── page.tsx │ ├── item-tik-toks │ │ └── page.tsx │ └── layout.tsx ├── videooptions │ ├── page.tsx │ └── videoptions.tsx ├── view-my-requests │ ├── addtogallery.tsx │ ├── page.tsx │ ├── requesttable.tsx │ └── test.json ├── waitlist │ ├── oldpage.tsx │ ├── page.tsx │ └── subscribe.tsx └── xloader.tsx ├── components.json ├── components ├── About │ ├── AboutSectionOne.tsx │ └── AboutSectionTwo.tsx ├── Blog │ ├── RelatedPost.tsx │ ├── SharePost.tsx │ ├── SingleBlog.tsx │ ├── TagButton.tsx │ ├── blogData.tsx │ └── index.tsx ├── Brands │ └── index.tsx ├── Common │ ├── Breadcrumb.tsx │ ├── BreadcrumbCustom.tsx │ ├── FieldGroup.tsx │ ├── FontDefInput.tsx │ ├── LoadingOverlay.tsx │ ├── MyVideoComboBox.tsx │ ├── OutOfCreditsAlert.tsx │ ├── OutOfCreditsAlertAI.tsx │ ├── PostAIModal.tsx │ ├── ScrollUp.tsx │ ├── SectionTitle.tsx │ ├── TextHighlight.tsx │ └── WaitingOverlay.tsx ├── Contact │ ├── NewsLatterBox.tsx │ └── index.tsx ├── CreateVideoOptions │ └── index.tsx ├── DataProvider │ └── index.tsx ├── FAQ │ ├── faqdata.tsx │ └── index.tsx ├── Features │ ├── SingleFeature.tsx │ ├── featuresData.tsx │ └── index.tsx ├── Footer │ └── index.tsx ├── Header │ ├── ThemeToggler.tsx │ ├── index.tsx │ └── menuData.tsx ├── Hero │ ├── index.tsx │ └── textanim.tsx ├── HowTo │ ├── SingleHowto.tsx │ ├── howtoData.tsx │ └── index.tsx ├── Item │ └── AddItemBtn.tsx ├── Pricing │ ├── OfferList.tsx │ ├── PricingBox.tsx │ └── index.tsx ├── ScrollToTop │ └── index.tsx ├── Testimonials │ ├── SingleTestimonial.tsx │ └── index.tsx ├── Video │ └── index.tsx ├── blank.tsx ├── mtexport.ts └── ui │ ├── accordion.tsx │ ├── badge.tsx │ ├── button.tsx │ ├── card.tsx │ ├── checkbox.tsx │ ├── collapsible.tsx │ ├── command.tsx │ ├── dialog.tsx │ ├── drawer.tsx │ ├── input.tsx │ ├── label.tsx │ ├── popover.tsx │ ├── progress.tsx │ ├── select.tsx │ └── tooltip.tsx ├── dbutil ├── ap2mongo.ts ├── dbmain.ts ├── gallerydb.ts ├── itemsdb.ts ├── ledgerdb.ts ├── mymongodb.ts ├── mymongodb_orig.ts ├── userdb.ts ├── videoreqdb.ts └── waitlistdb.ts ├── hooks └── use-media-query.ts ├── jsconfig.json ├── lib └── utils.ts ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── audio │ ├── audio-test1.mp3 │ ├── chill.mp3 │ ├── dramatic.mp3 │ ├── relaxed.mp3 │ ├── rock.mp3 │ └── upbeat.mp3 ├── favicon.ico └── images │ ├── 1ClickVideo.png │ ├── 404.svg │ ├── AIAPIIntro.png │ ├── AIVideo_Image.jpg │ ├── DataVids-Editor.png │ ├── DataVids1.png │ ├── DataVids1_OG.png │ ├── DataVids1_wide.png │ ├── TurnContent.png │ ├── TurnContentTwitter.png │ ├── WizardVideo_Image.jpg │ ├── about │ ├── about-image-2.svg │ └── about-image.svg │ ├── ai-anim.gif │ ├── ai.png │ ├── blog │ ├── author-01.png │ ├── author-02.png │ ├── author-03.png │ ├── blog-01.jpg │ ├── blog-02.jpg │ ├── blog-03.jpg │ ├── blog-details-01.jpg │ ├── blog-details-02.jpg │ ├── post-01.jpg │ ├── post-02.jpg │ └── post-03.jpg │ ├── brands │ ├── ecommerce-html.svg │ ├── graygrids.svg │ ├── lineicons.svg │ ├── tailadmin.svg │ ├── tailgrids.svg │ └── uideck.svg │ ├── favicon.ico │ ├── hero │ ├── shape-01.svg │ └── shape-02.svg │ ├── icons │ ├── icon.png │ └── oldicon.png │ ├── logo │ ├── datavids-1.png │ ├── logo-2.svg │ └── logo4.png │ ├── main.png │ ├── og.png │ ├── og_vertical.png │ ├── screenshot.png │ ├── screenshot1.jpg │ ├── teaserimage.png │ ├── testimonials │ ├── auth-01.png │ ├── auth-02.png │ ├── auth-03.png │ ├── author-01.png │ ├── author-02.png │ └── author-03.png │ ├── token.png │ └── video │ ├── shape.svg │ └── video.jpg ├── remotion-video ├── Composition.tsx ├── README.md ├── Root.tsx ├── common │ ├── DVImage.tsx │ ├── FontFactory.ts │ ├── TextBubble.tsx │ ├── TextCaption.tsx │ └── tts │ │ └── ttsclient.ts ├── index.ts ├── samples │ ├── default.ts │ └── sample2.json ├── simple │ ├── Body.tsx │ └── simple.tsx ├── style.css ├── types │ ├── bgaudio.ts │ ├── test.ts │ └── uservideodef.ts └── webpack-override.ts ├── remotion.config.ts ├── styles └── index.css ├── tailwind.config.js ├── test-pnpm-lock.yaml ├── tsconfig.json ├── types ├── blog.ts ├── brand.ts ├── faqitem.ts ├── feature.ts ├── gallery.ts ├── howto.ts ├── item.ts ├── ledger.ts ├── menu.ts ├── next-auth.d.ts ├── product.ts ├── testimonial.ts ├── userdetails.ts ├── uservideodef.ts └── uservideoreq.ts ├── utils ├── api-helpers.ts ├── authutil.ts ├── ledgerutil.ts ├── mycheerio.ts ├── pexels.ts ├── stripe.ts ├── urltovideoai.ts ├── verificationemail.ts └── vidutil.ts └── vercel.json /.env.sample: -------------------------------------------------------------------------------- 1 | GOOGLE_CLIENT_ID="" 2 | GOOGLE_CLIENT_SECRET="" 3 | MAIN_DB="ap2template" 4 | MONGODB_URI="mongodb+srv:" 5 | NEXTAUTH_SECRET="" 6 | NEXTAUTH_URL="http://localhost:3000" 7 | NEXT_PUBLIC_SITENAME="AP2 Template" 8 | SMTP_SERVER="smtp://apikey:@smtp.sendgrid.net:587" 9 | 10 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .vscode 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apsquared/datavids_public/0889afd559320fc2f8e564cbbcee8cedcbcc9ee6/.prettierrc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Next.js Templates 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DATAVIDS 2 | 3 | ## Background 4 | 5 | DataVids was created as a side project to help promote my other two sites [BarGPT, AI Cocktail Creator](https://www.bargpt.app) and [TVFoodMaps](https://www.tvfoodmaps.com) promote their content on TikTok. After finding the awesome [Remotion](https://www.remotion.dev/) project I decided to try and build 6 | a full SaaS video creation site. 7 | 8 | ## What Happened 9 | 10 | After building the site it became clear that keeping up with the many projects in this area would take more effort than I was willing to put in and I didn't want to offer a product that was inferior to people. Also at the same time I came to the realization that projects like BarGPT and TVFoodMaps are more my speed. 11 | 12 | ## So what next? 13 | 14 | Instead of the site just being a total waste, I figured I'd make the source open to anyone who wants to learn any of the following: 15 | 16 | * Remotion 17 | * NextJS (with app router) 18 | * Stripe Integraion 19 | * Using Lambdas to render videos 20 | * Basic AI for creating videos 21 | 22 | There is a lot of great content inside this code. Look it over, learn from it, steal it. 23 | 24 | ## Thanks! How can I help? 25 | 26 | Of course you can visit and help promote [BarGPT, AI Cocktail Creator](https://www.bargpt.app) and [TVFoodMaps](https://www.tvfoodmaps.com). You can also [follow me on X](https://twitter.com/APSquaredDev). 27 | 28 | 29 | ## Fine Print - Please Read. 30 | 31 | All of this code is available AS-IS with no warranty or support. It's just a learning tool. -------------------------------------------------------------------------------- /app/about/page.tsx: -------------------------------------------------------------------------------- 1 | import AboutSectionOne from "@/components/About/AboutSectionOne"; 2 | import AboutSectionTwo from "@/components/About/AboutSectionTwo"; 3 | import Breadcrumb from "@/components/Common/Breadcrumb"; 4 | 5 | const AboutPage = () => { 6 | return ( 7 | <> 8 | 12 | 13 | 14 | 15 | ); 16 | }; 17 | 18 | export default AboutPage; 19 | -------------------------------------------------------------------------------- /app/admin/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { redirect } from 'next/navigation' 4 | import Breadcrumb from '@/components/Common/Breadcrumb'; 5 | import { Input } from "@/components/mtexport"; 6 | import AdminPage from './adminpage'; 7 | import { getRequestCountByStatus,getRequestCountByStatusNotUs } from '@/dbutil/videoreqdb'; 8 | 9 | 10 | 11 | const AdminP = async() => { 12 | 13 | const session = await getServerSession( authOptions); 14 | 15 | if (!session || !session.user || session.user.role!="ADMIN"){ 16 | redirect('/signin'); 17 | return; 18 | } 19 | 20 | const counts = await getRequestCountByStatusNotUs(); 21 | 22 | return ( 23 | 24 | 25 | ) 26 | } 27 | 28 | export default AdminP -------------------------------------------------------------------------------- /app/admin/videolist/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { redirect } from 'next/navigation' 4 | import Breadcrumb from '@/components/Common/Breadcrumb'; 5 | import { Input } from "@/components/mtexport"; 6 | import VidList from './vidlist'; 7 | import { getRequestCountByStatus, getVideoRequestsByStatusNotUs } from '@/dbutil/videoreqdb'; 8 | 9 | 10 | 11 | const AdminP = async({searchParams}:{searchParams: { [key: string]: string | string[] | undefined }}) => { 12 | 13 | const session = await getServerSession( authOptions); 14 | 15 | if (!session || !session.user || session.user.role!="ADMIN"){ 16 | redirect('/signin'); 17 | return; 18 | } 19 | let status; 20 | if (searchParams && searchParams['status']){ 21 | status = searchParams['status'] as string; 22 | } 23 | let videoList=await getVideoRequestsByStatusNotUs(+status!); 24 | 25 | return ( 26 | <> 27 | 31 |
32 |
33 | 34 |
35 |
36 | 37 | 38 | ) 39 | } 40 | 41 | export default AdminP -------------------------------------------------------------------------------- /app/api/addtogallery/route.ts: -------------------------------------------------------------------------------- 1 | 2 | import { addToGallery } from '@/dbutil/gallerydb'; 3 | import { NextRequest } from 'next/server'; 4 | import { authOptions } from '@/utils/authutil'; 5 | import { getServerSession } from 'next-auth'; 6 | 7 | export async function POST(request: NextRequest) { 8 | 9 | const session = await getServerSession( authOptions); 10 | 11 | const body = await request.json() // res now contains body 12 | 13 | const url = body.url; 14 | const name = body.name; 15 | const link = body.link; 16 | const desc = body.description; 17 | try{ 18 | let resp=await addToGallery(session?.user?.id!,name,url,"",link,desc); 19 | return new Response(JSON.stringify({"added": true}) 20 | , { 21 | status:200, 22 | headers: { 23 | 'content-type': 'application/json', 24 | }, 25 | }); 26 | 27 | } catch (err) { 28 | const errorMessage = 29 | err instanceof Error ? err.message : 'Internal server error' 30 | return new Response("", { 31 | status: 500, 32 | headers: { 33 | 'content-type': 'application/json', 34 | }, 35 | }); 36 | 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /app/api/addtowaitlist/route.ts: -------------------------------------------------------------------------------- 1 | 2 | import { addToWaitlist } from '@/dbutil/waitlistdb'; 3 | import { NextRequest } from 'next/server'; 4 | 5 | export async function POST(request: NextRequest) { 6 | 7 | ////console.log("here"); 8 | const body = await request.json() // res now contains body 9 | 10 | const email = body.email; 11 | 12 | let resp = { 13 | status: 'OK', 14 | } 15 | 16 | if (isValidEmail(email)){ 17 | await addToWaitlist(email); 18 | } else { 19 | resp.status = "Invalid Email"; 20 | } 21 | 22 | 23 | return new Response(JSON.stringify({resp}), { 24 | status: 200, 25 | headers: { 26 | 'content-type': 'application/json', 27 | }, 28 | }); 29 | } 30 | 31 | function isValidEmail(email: string): boolean { 32 | const emailRegex: RegExp = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/; 33 | return emailRegex.test(email); 34 | } 35 | -------------------------------------------------------------------------------- /app/api/aigetwebcontent/route.ts: -------------------------------------------------------------------------------- 1 | import { authOptions } from "@/utils/authutil"; 2 | import { getServerSession } from "next-auth"; 3 | import { AI_COST, addAICreationToLeder } from "@/utils/ledgerutil"; 4 | import { getUserCreditBalance } from "@/dbutil/ledgerdb"; 5 | import { getWebsiteData } from "@/utils/urltovideoai"; 6 | 7 | 8 | /* not yet implemented */ 9 | export async function POST(request: Request) { 10 | ////console.log("here"); 11 | 12 | const json = await request.json(); 13 | const url = json.url; 14 | 15 | const session = await getServerSession( authOptions); 16 | 17 | if (!session || !session.user){ 18 | return new Response('Unauthorized', {status: 401,}); 19 | } 20 | 21 | console.log("Gathering webdata for "+url); 22 | //check credit count 23 | let creditbalance=await getUserCreditBalance(session.user.id); 24 | if(creditbalance < AI_COST) 25 | { 26 | return new Response('NotEnoughCredits', {status: 410}); 27 | } 28 | 29 | const {webdata,metadata} = await getWebsiteData(url); 30 | return new Response(JSON.stringify({webdata,metadata}), { 31 | status: 200, 32 | headers: { 33 | 'content-type': 'application/json', 34 | }, 35 | }); 36 | 37 | } -------------------------------------------------------------------------------- /app/api/aiimgtovid/route.ts: -------------------------------------------------------------------------------- 1 | 2 | import Replicate from "replicate"; 3 | 4 | const auth = "r8_R2W8T97dXxA3cu5MXQ9I7JdOolPJchs1tR5oM" 5 | export const maxDuration = 60; // This function can run for a maximum of 60 seconds 6 | 7 | 8 | //https://replicate.com/docs/webhooks 9 | 10 | export async function GET(request: Request) { 11 | 12 | ////console.log("here"); 13 | const { searchParams } = new URL(request.url); 14 | const imgurl = searchParams.get("imgurl"); 15 | 16 | console.log("IMGURL "+imgurl) 17 | 18 | const replicate = new Replicate({ 19 | auth: auth, 20 | }); 21 | 22 | 23 | const output = await replicate.run( 24 | "stability-ai/stable-video-diffusion:3f0457e4619daac51203dedb472816fd4af51f3149fa7a9e0b5ffcf1b8172438", 25 | { 26 | input: { 27 | cond_aug: 0.02, 28 | decoding_t: 7, //use 14 for 25 frame 29 | input_image: imgurl, 30 | video_length: "14_frames_with_svd", //25_frames_with_svd_x 31 | sizing_strategy: "maintain_aspect_ratio", 32 | motion_bucket_id: 127, 33 | frames_per_second: 5 34 | } 35 | } 36 | ); 37 | console.log(output); 38 | 39 | 40 | return new Response(JSON.stringify({videourl:output}), { 41 | status: 200, 42 | headers: { 43 | 'content-type': 'application/json', 44 | }, 45 | }); 46 | 47 | } -------------------------------------------------------------------------------- /app/api/auth/[...nextauth]/route.ts: -------------------------------------------------------------------------------- 1 | import NextAuth from "next-auth" 2 | import {authOptions} from "@/utils/authutil" 3 | 4 | 5 | const handler = NextAuth(authOptions); 6 | 7 | export { handler as GET, handler as POST } 8 | 9 | -------------------------------------------------------------------------------- /app/api/createitem/route.ts: -------------------------------------------------------------------------------- 1 | import {createItem} from '@/dbutil/itemsdb' 2 | import {Item} from '@/types/item' 3 | import { NextRequest } from 'next/server'; 4 | 5 | export async function POST(request: NextRequest) { 6 | 7 | ////console.log("here"); 8 | const body = await request.json() // res now contains body 9 | 10 | const itm : Item = { 11 | name: body.name, 12 | description: body.description, 13 | link: body.link, 14 | } 15 | 16 | const resp:boolean = await createItem(itm); 17 | 18 | return new Response(JSON.stringify({resp}), { 19 | status: 200, 20 | headers: { 21 | 'content-type': 'application/json', 22 | }, 23 | }); 24 | 25 | 26 | } -------------------------------------------------------------------------------- /app/api/createvideo/samples.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | curl -X POST http://localhost:3000/api/createvideo \ 4 | -H "Content-Type: application/json" \ 5 | -H "datavids-api-key: HIz2VKDOPCbeZCeg" \ 6 | -d '{"videoDef":{"videoname":"test from api"},"templateID":"6556ccb998d182b0c95b489e"}' 7 | 8 | */ -------------------------------------------------------------------------------- /app/api/createvideorequest/route.ts: -------------------------------------------------------------------------------- 1 | import { getUserCreditBalance } from '@/dbutil/ledgerdb'; 2 | import { createVideoRequest, getAllVideoRequests, resaveVideoRequest } from '@/dbutil/videoreqdb'; 3 | import {UserVideoDef} from '@/types/uservideodef' 4 | import { UserVideoRequest, VideoStatus } from '@/types/uservideoreq'; 5 | import { authOptions } from '@/utils/authutil'; 6 | import { AI_COST, addUserActionToLedger } from '@/utils/ledgerutil'; 7 | import { getServerSession } from 'next-auth'; 8 | import { revalidatePath } from 'next/cache'; 9 | import { NextRequest } from 'next/server'; 10 | 11 | export async function POST(request: NextRequest) { 12 | 13 | ////console.log("here"); 14 | const json = await request.json() // res now contains body 15 | 16 | const uservid = json.uservid; 17 | const videoid = json.videoid; 18 | 19 | const session = await getServerSession( authOptions); 20 | 21 | if (!session || !session.user){ 22 | return new Response('Unauthorized', {status: 401,}); 23 | } 24 | let cost=1*Math.ceil(uservid.durationSec!/10); 25 | let creditbalance=await getUserCreditBalance(session.user.id); 26 | if(creditbalance < cost) 27 | { 28 | return new Response('NotEnoughCredits', {status: 410,}); 29 | } 30 | cost=cost*-1; //set to negative for the ledger later 31 | //console.log(JSON.stringify(uservid)); 32 | if (videoid && videoid.length>1){ 33 | //already saved object 34 | console.log("Adding existing video to queue"); 35 | const vidreq : UserVideoRequest = { 36 | userid:session.user.id, 37 | videoDef:uservid, 38 | status:VideoStatus.QUEUED, 39 | updateTime: new Date(), 40 | } 41 | const resp:string = await resaveVideoRequest(videoid,vidreq); 42 | await addUserActionToLedger(session.user.id,"RENDER",resp,cost,"Rendering of video"); 43 | return new Response(JSON.stringify({id:resp}), { 44 | status: 200, 45 | headers: { 46 | 'content-type': 'application/json', 47 | }, 48 | }); 49 | } 50 | else { 51 | console.log("Adding new video to queue"); 52 | const vidreq : UserVideoRequest = { 53 | userid:session.user.id, 54 | videoDef:uservid, 55 | status:VideoStatus.QUEUED, 56 | requestTime: new Date(), 57 | updateTime: new Date(), 58 | } 59 | 60 | const resp:string = await createVideoRequest(vidreq); 61 | await addUserActionToLedger(session.user.id,"RENDER",resp,cost,"Rendering of video"); 62 | return new Response(JSON.stringify({id:resp}), { 63 | status: 200, 64 | headers: { 65 | 'content-type': 'application/json', 66 | }, 67 | }); 68 | } 69 | 70 | 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /app/api/getcount/route.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | export type Count = { 4 | count:number, 5 | type:string, 6 | } 7 | //console.log("TEST"); 8 | 9 | export async function GET(request: Request) { 10 | 11 | ////console.log("here"); 12 | const { searchParams } = new URL(request.url); 13 | const type = searchParams.get("type"); 14 | 15 | 16 | return new Response(JSON.stringify({count:Math.random(),type:type}), { 17 | status: 200, 18 | headers: { 19 | 'content-type': 'application/json', 20 | }, 21 | }); 22 | 23 | } -------------------------------------------------------------------------------- /app/api/getusercredits/route.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest } from 'next/server'; 2 | import { authOptions } from '@/utils/authutil'; 3 | import { getServerSession } from 'next-auth'; 4 | import { Ledger } from '@/types/ledger'; 5 | import { getUserCreditBalance } from '@/dbutil/ledgerdb'; 6 | 7 | export async function GET(request: Request) { 8 | 9 | ////console.log("here"); 10 | const session = await getServerSession( authOptions); 11 | let credits=await getUserCreditBalance(session?.user?.id!); 12 | return new Response(JSON.stringify({total:credits}), { 13 | status: 200, 14 | headers: { 15 | 'content-type': 'application/json', 16 | }, 17 | }); 18 | 19 | } -------------------------------------------------------------------------------- /app/api/getvideorequestbyid/route.ts: -------------------------------------------------------------------------------- 1 | import { getVideoRequestById } from "@/dbutil/videoreqdb"; 2 | import { UserVideoRequest } from "@/types/uservideoreq"; 3 | import { NextRequest } from "next/server"; 4 | 5 | 6 | export async function GET(request: NextRequest) { 7 | 8 | const { searchParams } = new URL(request.url); 9 | const id = searchParams.get("id"); 10 | 11 | console.log("Loading") 12 | 13 | if (!id){ 14 | return new Response(JSON.stringify({"status":"id not found"}), { 15 | status: 404, 16 | headers: { 17 | 'content-type': 'application/json', 18 | }, 19 | }); 20 | } 21 | 22 | const vidReq:UserVideoRequest = await getVideoRequestById(id); 23 | 24 | 25 | return new Response(JSON.stringify(vidReq), { 26 | status: 200, 27 | headers: { 28 | 'content-type': 'application/json', 29 | }, 30 | }); 31 | 32 | } -------------------------------------------------------------------------------- /app/api/pexels/route.ts: -------------------------------------------------------------------------------- 1 | import { DVVideoResult, findVerticalVideos } from "@/utils/pexels"; 2 | 3 | 4 | export async function GET(request: Request) { 5 | 6 | const { searchParams } = new URL(request.url); 7 | const query = searchParams.get("query"); 8 | 9 | if (query){ 10 | const results:DVVideoResult[] = await findVerticalVideos(query as string); 11 | return new Response(JSON.stringify( {results:results} ), { 12 | status: 200, 13 | headers: { 14 | 'content-type': 'application/json', 15 | }, 16 | }); 17 | } else { 18 | return new Response(JSON.stringify({error:"missing query"}), { 19 | status: 200, 20 | headers: { 21 | 'content-type': 'application/json', 22 | }, 23 | }); 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /app/api/processqueue/route.ts: -------------------------------------------------------------------------------- 1 | import { getAllQueuedRequests, updateVidReq } from '@/dbutil/videoreqdb'; 2 | import { UserVideoRequest } from '@/types/uservideoreq'; 3 | import { startLambda } from '@/utils/vidutil'; 4 | import { NextRequest } from 'next/server'; 5 | 6 | export async function GET(request: NextRequest){ 7 | console.log(request.url); 8 | return POST(request); 9 | } 10 | 11 | 12 | export async function POST(request: NextRequest) { 13 | 14 | console.log ("cron job called"); 15 | 16 | const items:UserVideoRequest[] = await getAllQueuedRequests(); 17 | console.log("Queue items "+JSON.stringify(items) ); 18 | 19 | if (items.length==0){ 20 | return new Response(JSON.stringify({status:'no items'}), { 21 | status: 200, 22 | headers: { 23 | 'content-type': 'application/json', 24 | }, 25 | }); 26 | } 27 | 28 | let i = 0; 29 | const MAX_ITEMS = 3; 30 | 31 | for (let item of items){ 32 | const {renderId,bucketName} = await startLambda(item.videoDef); 33 | //update item with renderId and bucketName, start time, 34 | const result = await updateVidReq(item,renderId,bucketName); 35 | i++; 36 | if (i >= MAX_ITEMS){ 37 | break; 38 | } 39 | } 40 | 41 | return new Response(JSON.stringify({status:'ok'}), { 42 | status: 200, 43 | headers: { 44 | 'content-type': 'application/json', 45 | }, 46 | }); 47 | 48 | } -------------------------------------------------------------------------------- /app/api/saveonly/route.ts: -------------------------------------------------------------------------------- 1 | import { createVideoRequest, getAllVideoRequests, resaveVideoRequest } from '@/dbutil/videoreqdb'; 2 | import {UserVideoDef} from '@/types/uservideodef' 3 | import { UserVideoRequest, VideoStatus } from '@/types/uservideoreq'; 4 | import { authOptions } from '@/utils/authutil'; 5 | import { getServerSession } from 'next-auth'; 6 | import { revalidatePath } from 'next/cache'; 7 | import { NextRequest } from 'next/server'; 8 | 9 | export async function POST(request: NextRequest) { 10 | 11 | ////console.log("here"); 12 | const json = await request.json() // res now contains body 13 | 14 | const uservid = json.uservid; 15 | const videoid = json.videoid; 16 | 17 | const session = await getServerSession( authOptions); 18 | 19 | if (!session || !session.user){ 20 | return new Response('Unauthorized', {status: 401,}); 21 | } 22 | 23 | console.log(JSON.stringify(uservid)); 24 | 25 | if (!videoid){ 26 | //NEW VIDEO 27 | const vidreq : UserVideoRequest = { 28 | userid:session.user.id, 29 | videoDef:uservid, 30 | status:VideoStatus.SAVED, 31 | updateTime: new Date(), 32 | } 33 | 34 | const resp:string = await createVideoRequest(vidreq); 35 | return new Response(JSON.stringify({id:resp}), { 36 | status: 200, 37 | headers: { 38 | 'content-type': 'application/json', 39 | }, 40 | }); 41 | } else { 42 | //OLD VIDEO 43 | console.log("Existing video "+videoid); 44 | const vidreq : UserVideoRequest = { 45 | userid:session.user.id, 46 | videoDef:uservid, 47 | status:VideoStatus.SAVED, 48 | updateTime: new Date(), 49 | } 50 | const resp:string = await resaveVideoRequest(videoid,vidreq); 51 | return new Response(JSON.stringify({id:resp}), { 52 | status: 200, 53 | headers: { 54 | 'content-type': 'application/json', 55 | }, 56 | }); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /app/api/stripe/get_prices/route.ts: -------------------------------------------------------------------------------- 1 | import { NextApiRequest, NextApiResponse } from 'next' 2 | import { getUserDetails} from '../../../../dbutil/userdb' 3 | import { stripe } from '../../../../utils/stripe' 4 | import { getURL } from '../../../../utils/api-helpers'; 5 | import { NextRequest } from 'next/server'; 6 | 7 | 8 | export async function GET(request: NextRequest) { 9 | 10 | 11 | try { 12 | 13 | 14 | //const products = await stripe.products.list({active:true}); 15 | const prices = await stripe.prices.list({active:true}); 16 | 17 | return new Response(JSON.stringify({"data": prices.data}) 18 | , { 19 | status:200, 20 | headers: { 21 | 'content-type': 'application/json', 22 | }, 23 | }); 24 | 25 | } catch (err) { 26 | const errorMessage = 27 | err instanceof Error ? err.message : 'Internal server error' 28 | return new Response("", { 29 | status: 500, 30 | headers: { 31 | 'content-type': 'application/json', 32 | }, 33 | }); 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/api/tts/route.ts: -------------------------------------------------------------------------------- 1 | 2 | import { NextRequest } from 'next/server'; 3 | import { textToSpeech,TTS_RESULT } from './tts'; 4 | import { textToSpeechOAI } from './oaitts'; 5 | import { VALID_VOICES } from '@/remotion-video/common/tts/ttsclient'; 6 | 7 | export async function POST(request: NextRequest) { 8 | 9 | ////console.log("here"); 10 | const body = await request.json() // res now contains body 11 | 12 | const text = body.text; 13 | const voice = body.voice as keyof typeof VALID_VOICES; 14 | 15 | //console.log("TTS REQUEST request for "+text); 16 | 17 | 18 | let result:TTS_RESULT = {audiourl:'',durationMs:-1,}; 19 | if (voice.startsWith("oai")){ 20 | result = await textToSpeechOAI(text,voice) 21 | } else { 22 | result = await textToSpeech(text,voice) 23 | } 24 | 25 | 26 | //console.log("TTS RESULTS for "+text+" "+JSON.stringify(result)); 27 | 28 | return new Response(JSON.stringify(result), { 29 | status: 200, 30 | headers: { 31 | 'content-type': 'application/json', 32 | 'Access-Control-Allow-Origin': '*', 33 | 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 34 | 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 35 | }, 36 | }); 37 | } 38 | 39 | export async function OPTIONS(request: Request) { 40 | const allowedOrigin = request.headers.get("origin"); 41 | const response = new Response(null, { 42 | status: 200, 43 | headers: { 44 | "Access-Control-Allow-Origin": allowedOrigin || "*", 45 | "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", 46 | "Access-Control-Allow-Headers": 47 | "Content-Type, Authorization, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version", 48 | "Access-Control-Max-Age": "86400", 49 | }, 50 | }); 51 | 52 | return response; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /app/api/use_credits/route.ts: -------------------------------------------------------------------------------- 1 | 2 | import { NextRequest } from 'next/server'; 3 | import { authOptions } from '@/utils/authutil'; 4 | import { getServerSession } from 'next-auth'; 5 | import { addAdminGrantedCreditsToLedger, addUserActionToLedger } from '@/utils/ledgerutil'; 6 | import { addToLedger } from '@/dbutil/ledgerdb'; 7 | 8 | 9 | export async function POST(request: NextRequest) { 10 | 11 | 12 | try { 13 | const session = await getServerSession( authOptions); 14 | const json=await request.json(); 15 | let credits=json.credits as number; 16 | let userid=session?.user?.id!; 17 | 18 | if(userid==null || userid=="" || credits==0 || credits==null) 19 | { 20 | return new Response(JSON.stringify({"used": false}) 21 | , { 22 | status:400, 23 | headers: { 24 | 'content-type': 'application/json', 25 | }, 26 | }); 27 | } 28 | 29 | await addUserActionToLedger(userid,"ADJUST","",credits,"Manually Adjustment"); 30 | return new Response(JSON.stringify({"used": true}) 31 | , { 32 | status:200, 33 | headers: { 34 | 'content-type': 'application/json', 35 | }, 36 | }); 37 | 38 | } catch (err) { 39 | const errorMessage = 40 | err instanceof Error ? err.message : 'Internal server error' 41 | return new Response("", { 42 | status: 500, 43 | headers: { 44 | 'content-type': 'application/json', 45 | }, 46 | }); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/buycredits/OfferList.tsx: -------------------------------------------------------------------------------- 1 | const checkIcon = ( 2 | 3 | 4 | 5 | ); 6 | 7 | const crossIcon = ( 8 | 9 | 10 | 11 | ); 12 | 13 | const OfferList = ({ 14 | text, 15 | status, 16 | }: { 17 | text: string; 18 | status: "active" | "inactive"; 19 | }) => { 20 | return ( 21 |
22 | 23 | {status === "active" ? checkIcon : crossIcon} 24 | 25 |

{text}

26 |
27 | ); 28 | }; 29 | 30 | export default OfferList; 31 | -------------------------------------------------------------------------------- /app/buycredits/displayproducts.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { getServerSession } from 'next-auth' 3 | import {authOptions} from '@/utils/authutil' 4 | import { redirect } from 'next/navigation' 5 | import { useState,useEffect } from 'react'; 6 | import Breadcrumb from "@/components/Common/Breadcrumb"; 7 | import { useRouter } from "next/navigation"; 8 | import { Product } from '@/types/product'; 9 | import PricingBox from './PricingBox'; 10 | import OfferList from './OfferList'; 11 | import SectionTitle from '@/components/Common/SectionTitle'; 12 | 13 | const DisplayProducts = ({productsList}:{productsList:Product[]}) => { 14 | const router = useRouter(); 15 | const buyItem = (priceid: string) =>{ 16 | console.log("clicked for "+priceid); 17 | router.push('/checkout?priceid='+priceid); 18 | } 19 | 20 | return ( 21 | <> 22 | 26 |
27 |
28 | { productsList?.map((p:Product , index:number) => 29 | (
30 | 31 |
32 | 33 | 40 | 41 |
42 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
58 |
59 | 60 | 61 | 62 |
63 | 64 |
65 | 66 | ))} 67 | { productsList==null && ( 68 | <>Loading Products... 69 | )} 70 |
71 |
72 | 73 | ) 74 | } 75 | 76 | export default DisplayProducts -------------------------------------------------------------------------------- /app/buycredits/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { getProducts } from '@/dbutil/ledgerdb'; 4 | import DisplayProducts from './displayproducts'; 5 | import Breadcrumb from '@/components/Common/Breadcrumb'; 6 | 7 | const DisplayProducts2 = async() => { 8 | let priceid: string=""; 9 | let productlist=await getProducts(); 10 | console.log("returned this many products : "+productlist.length); 11 | return( 12 | <> 13 | 17 |
Sorry we are no longer operating on credits. If you are interested in DataVids please reach out to me on Twitter
18 | 19 | ) 20 | 21 | 22 | } 23 | 24 | export default DisplayProducts2 -------------------------------------------------------------------------------- /app/checkout/checkout.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | import { getServerSession } from 'next-auth' 3 | import {authOptions} from '@/utils/authutil' 4 | import { redirect } from 'next/navigation' 5 | import { useState,useEffect } from 'react'; 6 | import Breadcrumb from "@/components/Common/Breadcrumb"; 7 | import { useRouter } from "next/navigation"; 8 | 9 | import { loadStripe } from '@stripe/stripe-js'; 10 | import { 11 | EmbeddedCheckoutProvider, 12 | EmbeddedCheckout 13 | } from '@stripe/react-stripe-js'; 14 | import BreadcrumbCustom from '@/components/Common/BreadcrumbCustom'; 15 | 16 | 17 | const CheckoutPage = ({priceid}:{priceid:string}) => { 18 | const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!); 19 | const [clientSecret, setClientSecret] = useState(''); 20 | const router = useRouter(); 21 | 22 | 23 | useEffect(() => { 24 | fetch("/api/stripe/checkout_sessions", { 25 | method: "POST", 26 | body:JSON.stringify({priceid:priceid}) 27 | }) 28 | .then((res) => res.json()) 29 | .then((data) => setClientSecret(data.clientSecret)); 30 | }, []); 31 | 32 | 33 | const gotoWallet = () =>{ 34 | console.log("goto wallet"); 35 | router.push('/my-account'); 36 | 37 | } 38 | 39 | 40 | return ( 41 | <> 42 | 48 | {clientSecret && ( 49 | 53 | 54 | 55 | )} 56 | 57 | 58 | 59 | 60 | 61 | ) 62 | } 63 | 64 | export default CheckoutPage -------------------------------------------------------------------------------- /app/checkout/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { getProducts } from '@/dbutil/ledgerdb'; 4 | import CheckoutPage from './checkout'; 5 | import { redirect } from 'next/navigation' 6 | 7 | const Checkout = async({searchParams}:{searchParams: { [key: string]: string | string[] | undefined }}) => { 8 | let priceid: string=""; 9 | let productlist=await getProducts(); 10 | 11 | if (searchParams && searchParams['priceid']){ 12 | priceid = searchParams['priceid'] as string; 13 | } 14 | 15 | if(priceid!="") 16 | { 17 | return (<> 18 | 19 | 20 | ) 21 | }else{ 22 | redirect('/buycredits'); 23 | 24 | } 25 | 26 | } 27 | 28 | export default Checkout -------------------------------------------------------------------------------- /app/contact/page.tsx: -------------------------------------------------------------------------------- 1 | import Breadcrumb from "@/components/Common/Breadcrumb"; 2 | import Contact from "@/components/Contact"; 3 | 4 | const ContactPage = () => { 5 | return ( 6 | <> 7 | 11 |
12 |
13 |
14 |
15 |

16 | Contact Us 17 |

18 |

19 | We would love to hear from you. If you would like to reach out feel free to contact us on 20 | {" "}Twitter @DataVidsIO. 21 |

22 |

Or you can email 23 | us at datavids AT apsquared DOT co (that co not com!). 24 |

25 |
26 |
27 |
28 |
29 | {/**/} 30 | 31 | ); 32 | }; 33 | 34 | export default ContactPage; 35 | -------------------------------------------------------------------------------- /app/create-video-ai-url/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { redirect } from 'next/navigation' 4 | import { CreateVideoURL } from './createvideourl'; 5 | 6 | import { Metadata } from 'next'; 7 | 8 | 9 | 10 | const CreateVideoPage = async() => { 11 | 12 | const session = await getServerSession( authOptions); 13 | let loggedIn = false; 14 | 15 | if (session && session.user){ 16 | loggedIn = true; 17 | } 18 | 19 | 20 | //const userCredits = await getUserCreditBalance(session?.user?.id); 21 | return ( 22 | 23 | ) 24 | 25 | 26 | } 27 | 28 | export default CreateVideoPage; 29 | 30 | const mTitle = "URL to Video Creator Using AI, Get Started for FREE!"; 31 | const mDesc = "Just enter a URL to any webpage and DataVid's AI will create a TikTok ready video for you to go Viral with. Get started today for free!"; 32 | const mCan = '/' 33 | const img='/images/og.png' //need to update this 34 | 35 | export const metadata: Metadata = { 36 | title:mTitle, 37 | description:mDesc, 38 | keywords: ['Videos', 'Generate', 'TikTok','Viral','NoCode'], 39 | metadataBase: new URL("https://www.datavids.io"), 40 | alternates: { 41 | canonical: mCan, 42 | languages: { 43 | 'en-US': '/en-US', 44 | }, 45 | }, 46 | openGraph: { 47 | title: mTitle, 48 | description: mDesc, 49 | url: mCan, 50 | siteName: 'DataVids', 51 | type:'website', 52 | images: [{ 53 | url: img, 54 | alt:'BarGPT' 55 | } 56 | ] 57 | }, 58 | icons: { //need to make these work 59 | icon: '/images/icons/icon.png', 60 | shortcut: '/images/icons/icon.png', 61 | apple: '/images/icons/icon.png', 62 | other: { 63 | rel: '/images/icons/icon.png', 64 | url: '/images/icons/icon.png', 65 | }, 66 | }, 67 | twitter: { 68 | card: 'summary_large_image', 69 | title: mTitle, 70 | description: mDesc, 71 | site:'https://www.bargpt.app', 72 | creator: '@BarGPt', 73 | images: [img], 74 | }, 75 | } -------------------------------------------------------------------------------- /app/create-video-api/example.tsx: -------------------------------------------------------------------------------- 1 | 2 | export const dataVidIntro = { 3 | "videoname": "Default", 4 | "description": "This is a default video.", 5 | "videotype": "SINGLEITEM", 6 | "intro": { 7 | "image": "https://www.datavids.io/images/DataVids1.png", 8 | "title": "Want to turn your content into Viral Videos?", 9 | "tts": { 10 | "ttstext": "Want to turn your content into Viral Videos? ", 11 | } 12 | }, 13 | "body": { 14 | "item": { 15 | "itemname": "Introducing DataVids", 16 | "itemsubtitle": "Turn Content Into Videos In Seconds", 17 | "itemdetails": "No coding or video editing!", 18 | "image": "https://www.datavids.io/images/DataVids1.png", 19 | }, 20 | "outro": { 21 | "image": "https://www.datavids.io/images/screenshot1.jpg", 22 | "title": "This video was built in less than a minute!", 23 | "subtitle": "Visit DataVids.io to Learn More.", 24 | "tts": { 25 | "ttstext": "Even this video was built in less than a minute. Visit DataVids dot IO to learn more.", 26 | "voice": "enUSMan1" 27 | }, 28 | } 29 | } 30 | } 31 | 32 | const createAVideo = async () => { 33 | const valresponse = await fetch("/api/user/createvideo", { 34 | method: "POST", 35 | headers: { 36 | "Content-Type": "application/json", 37 | "api-token": "FD932FJF234DF9DFSKJFOIEFWEFC" 38 | }, 39 | body: JSON.stringify({templateID:"A1325432V434232",videoDef:dataVidIntro}) //SPECIFY AN EXISTING VIDEO AND THE OVERRIDES 40 | }); 41 | 42 | } -------------------------------------------------------------------------------- /app/create-video-api/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { redirect } from 'next/navigation' 4 | import { getUserCreditBalance } from '@/dbutil/ledgerdb'; 5 | import Breadcrumb from '@/components/Common/Breadcrumb'; 6 | 7 | 8 | 9 | const CreateVideoPage = async() => { 10 | 11 | const session = await getServerSession( authOptions); 12 | 13 | if (!session || !session.user){ 14 | redirect('/signin'); 15 | return; 16 | } 17 | const userCredits = await getUserCreditBalance(session?.user?.id); 18 | return ( 19 | <> 20 | 24 |

25 | API Details 26 |

27 |

28 | Coming Soon. 29 |

30 | 31 | ) 32 | 33 | 34 | } 35 | 36 | export default CreateVideoPage -------------------------------------------------------------------------------- /app/create-video-json/datavidintro.tsx: -------------------------------------------------------------------------------- 1 | import { RemotionUserVideoDef } from "@/remotion-video/types/uservideodef"; 2 | 3 | export const dataVidIntro:RemotionUserVideoDef = { 4 | "videoname": "Default", 5 | "description": "This is a default video.", 6 | "videotype": "SIMPLE", 7 | "durationSec": 15, 8 | "body": { 9 | "items": [{ 10 | "id": 1, 11 | "itemname": "Introducing DataVids", 12 | "itemsubtitle": "Turn Content Into Videos In Seconds", 13 | "itemdetails": "No coding or video editing!", 14 | "image": "https://www.datavids.io/images/DataVids1.png", 15 | "imageeffect": "SQUARE", 16 | "itemnamefont": { 17 | "fontname": "Poppins", 18 | "fontsize": 80, 19 | "fontcolor": "#FFFFFF", 20 | "bgcolor": "#4A6CF799" 21 | }, 22 | "itemsubtitlefont": { 23 | "fontname": "Poppins", 24 | "fontsize": 70, 25 | "fontcolor": "#FFFFFF", 26 | "bgcolor": "#4A6CF799" 27 | }, 28 | "itemdetailsfont": { 29 | "fontname": "Poppins", 30 | "fontsize": 60, 31 | "fontcolor": "#FFFFFF", 32 | "bgcolor": "#00000A80" 33 | }, 34 | "tts": { 35 | "ttstext": "Introducing DataVids, Turn Content Into Videos In Seconds", 36 | "voice": "enUSMan1" 37 | }, 38 | "itemduration": 5, 39 | }] 40 | }, 41 | 42 | } -------------------------------------------------------------------------------- /app/create-video-json/editor.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from 'react'; 2 | 3 | interface JsonEditorProps { 4 | initialJson?: string; 5 | onJsonUpdate?: (json: any) => void; 6 | } 7 | 8 | const JsonEditor: React.FC = ({ initialJson = '', onJsonUpdate }) => { 9 | if (initialJson) { 10 | let obj = JSON.parse(initialJson); 11 | if (obj){ 12 | initialJson = JSON.stringify(obj, null, 2) 13 | } 14 | } 15 | const [input, setInput] = useState(initialJson); 16 | const [parsedJson, setParsedJson] = useState(null); 17 | const [error, setError] = useState(null); 18 | const textareaRef = useRef(null); 19 | 20 | const handleValidate = () => { 21 | try { 22 | const parsed = JSON.parse(input); 23 | setParsedJson(parsed); 24 | setError(null); 25 | 26 | // Call the provided callback with the parsed JSON 27 | if (onJsonUpdate) { 28 | onJsonUpdate(parsed); 29 | } 30 | 31 | } catch (e:any) { 32 | setError(e.message); 33 | setParsedJson(null); 34 | } 35 | }; 36 | 37 | const renderLineNumbers = () => { 38 | const lineCount = input.split('\n').length; 39 | const lineNumbers = Array.from({ length: lineCount }, (_, i) => i + 1).join('\n'); 40 | return lineNumbers; 41 | }; 42 | 43 | useEffect(() => { 44 | if (textareaRef.current) { 45 | textareaRef.current.style.height = 'auto'; 46 | textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; 47 | } 48 | handleValidate(); 49 | }, [input]); 50 | 51 | return ( 52 |
53 |
54 |
{renderLineNumbers()}
55 | 63 |
64 | 65 | 66 | {error &&

{error}

} 67 | 68 | 69 |
70 | ); 71 | }; 72 | 73 | export default JsonEditor; 74 | -------------------------------------------------------------------------------- /app/create-video-json/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { redirect } from 'next/navigation' 4 | import { CreateVideoJSON } from './jsonedit'; 5 | 6 | 7 | 8 | const CreateVideoPage = async() => { 9 | 10 | const session = await getServerSession( authOptions); 11 | if (!session || !session.user){ 12 | redirect('/signin'); 13 | return; 14 | } 15 | 16 | return ( 17 | 18 | ) 19 | 20 | 21 | } 22 | 23 | export default CreateVideoPage -------------------------------------------------------------------------------- /app/create-video/defaults.ts: -------------------------------------------------------------------------------- 1 | import { RemotionUserVideoDef,ItemDetails, VideoBody, VideoType, VideoTypeSchema, FontDef, ImageEffectEnum, TextTypeEnum, TextLocationEnum } from "@/remotion-video/types/uservideodef"; 2 | 3 | 4 | 5 | export function getDefaultItemNameFont():FontDef{ 6 | return { 7 | fontname: 'montserrat', 8 | fontsize: 100, 9 | fontcolor: 'white', 10 | bgcolor: 'black', 11 | } 12 | } 13 | 14 | export function getDefaultSubtitleFont():FontDef{ 15 | return { 16 | fontname: 'montserrat', 17 | fontsize: 50, 18 | fontcolor: 'white', 19 | bgcolor: 'black', 20 | } 21 | } 22 | 23 | export function getDefaultItemDetails(id:number):ItemDetails{ 24 | return { 25 | id:id, 26 | itemname: '', 27 | image: '', 28 | itemsubtitle: '', 29 | itemdetails:'', 30 | texttype:TextTypeEnum.Values.CAPTIONS, 31 | textlocation:TextLocationEnum.Values.TOP, 32 | itemnamefont: getDefaultItemNameFont(), 33 | itemsubtitlefont: getDefaultSubtitleFont(), 34 | itemdetailsfont: getDefaultSubtitleFont(), 35 | imageeffect: ImageEffectEnum.Values.SQUARE, 36 | itemduration:5, 37 | itemnametop:225, 38 | itemsubtitletop:1450, 39 | tts:{ 40 | ttstext:'', 41 | voice:'oaialloy' 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/create-video/page.tsx: -------------------------------------------------------------------------------- 1 | import { getServerSession } from 'next-auth' 2 | import {authOptions} from '@/utils/authutil' 3 | import { redirect } from 'next/navigation' 4 | import { getUserVideoRequests } from '@/dbutil/videoreqdb' 5 | import CreateVideo2 from './createvideo2' 6 | 7 | 8 | const CreateVideoPage = async({searchParams}:{searchParams: { [key: string]: string | string[] | undefined }}) => { 9 | 10 | const session = await getServerSession( authOptions); 11 | 12 | if (!session || !session.user){ 13 | redirect('/signin'); 14 | return; 15 | } 16 | 17 | const userid = session.user.id; 18 | const results = await getUserVideoRequests(userid); 19 | 20 | let templateId:string | undefined = undefined; 21 | if (searchParams && searchParams['videoid']){ 22 | templateId = searchParams['videoid'] as string; 23 | } 24 | let fromAI:boolean = false; 25 | if (searchParams && searchParams['fromAI']){ 26 | if (searchParams['fromAI'] == 'true'){ 27 | fromAI = true; 28 | } 29 | } 30 | 31 | return ( 32 | 33 | ) 34 | } 35 | 36 | export default CreateVideoPage -------------------------------------------------------------------------------- /app/create-video/temp.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { Button } from "@/components/ui/button" 3 | import { CardContent, Card } from "@/components/ui/card" 4 | 5 | export default function Component() { 6 | return ( 7 |
8 |
9 |

Scenes

10 |
11 | 12 | 13 | Scene 1 14 | 17 | 18 | 19 | 20 | 21 | Scene 2 22 | 25 | 26 | 27 |
28 | 29 |
30 |
31 |

Scene Details

32 |
33 |
34 |

Scene Name

35 | 36 |
37 |
38 |

Scene Description

39 |