├── requirements.txt ├── .eslintrc.json ├── docs ├── frame_02.jpg └── screenshot.png ├── public └── favicon.ico ├── components ├── box.tsx ├── output.tsx ├── tabs.tsx └── video-form.tsx ├── scripts ├── test.py ├── download-audio.sh ├── split.sh ├── transcribe.py └── translate.py ├── next.config.js ├── .prettierrc.yaml ├── .gitignore ├── tsconfig.json ├── pages ├── _document.tsx ├── api │ ├── audio.ts │ ├── translate.ts │ └── transcript.ts └── index.tsx ├── package.json ├── utils ├── shell.ts └── api-client.ts ├── LICENSE ├── README.md └── stitches.config.ts /requirements.txt: -------------------------------------------------------------------------------- 1 | openai 2 | yt-dlp 3 | pysrt 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /docs/frame_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craftzdog/vlog-translator/HEAD/docs/frame_02.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craftzdog/vlog-translator/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craftzdog/vlog-translator/HEAD/docs/screenshot.png -------------------------------------------------------------------------------- /components/box.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from '@stitches/react' 2 | 3 | export const Box = styled('div', {}) 4 | -------------------------------------------------------------------------------- /scripts/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import openai 3 | openai.api_key = os.getenv('OPENAI_API_KEY') 4 | print(openai.Model.list()) 5 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | arrowParens: 'avoid' 2 | singleQuote: true 3 | bracketSpacing: true 4 | endOfLine: 'lf' 5 | semi: false 6 | tabWidth: 2 7 | trailingComma: 'none' 8 | -------------------------------------------------------------------------------- /scripts/download-audio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VIDEO_ID=$1 4 | 5 | [ -z "$VIDEO_ID" ] && echo "ERROR: No video ID specified" && exit 1 6 | 7 | yt-dlp "https://www.youtube.com/watch?v=$VIDEO_ID" --format m4a -o "./tmp/%(id)s.%(ext)s" 2>&1 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | tmp 3 | 4 | # dependencies 5 | /node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /scripts/split.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | # Description: Split an 3 | # Requires: ffmpeg, jq 4 | # Author: Hasan Arous 5 | # License: MIT 6 | 7 | set in $argv[1] 8 | set out $argv[2] 9 | set splits "" 10 | set chapters (ffprobe -i $in -print_format json -show_chapters | jq -r '.chapters[] | .start_time + " " + .end_time') 11 | 12 | for chapter in $chapters 13 | set start_time (echo $chapter | awk '{print $1}') 14 | set end_time (echo $chapter | awk '{print $2}') 15 | echo $start_time '|' $end_time 16 | ffmpeg -i "$in" -c copy -ss $start_time -to $end_time $out/$start_time.m4a 17 | end 18 | 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Head, Html, Main, NextScript } from 'next/document' 2 | import { getCssText, globalCss } from '../stitches.config' 3 | 4 | const globalStyles = globalCss({ 5 | body: { fontFamily: '$system', padding: 0, margin: 0 } 6 | }) 7 | 8 | export default function MyDocument() { 9 | globalStyles() 10 | 11 | return ( 12 | 13 | 14 |