Compare commits

5 Commits

Author SHA1 Message Date
Agent Developer
d7b827f28d fix: update Mautic contact form link to form/2 (BatchTube Support) 2026-03-10 03:47:32 +01:00
Agent Developer
0b6472b810 ci: add Windows build workflow (PyInstaller + NSIS)
- Triggers on version tags (v*) or workflow_dispatch
- Builds BatchTube.exe via PyInstaller
- Creates BatchTube-Setup-*.exe via NSIS
- Uploads artifacts for download
2026-03-09 23:47:13 +00:00
Agent Developer
7ddebce93b feat: update landing page - Studio tier, affiliates page, Mautic contact
- Added Studio tier at $79/mo or $790/yr
- Added affiliates.html with 30% commission program
- Replaced footer email with Mautic contact form link
- Added Affiliates nav link
- Added deploy-web.sh for server deployment
2026-03-09 23:44:14 +00:00
Agent Developer
c9041bde01 feat: enforce free tier limits (3 videos/batch, 720p max)
- config.py: add BATCHTUBE_PLAN env var, FREE_TIER_MAX_VIDEOS=3,
  FREE_TIER_MAX_RESOLUTION=720, PLAN_LIMITS map for all tiers
- api_server.py: cap resolution to 720p on free plan, reject CSV
  batches > 3 videos with 403 + upgrade prompt
- worker.py: truncate resolved video list to max_videos on free plan,
  emit tier_limit SSE event with upgrade message

Pricing tiers (2026-03-07 approved):
  Free: 3 videos/batch, 720p | Creator: $19/mo | Pro: $39/mo
  Studio: $79/mo | Lifetime: $197
2026-03-08 00:56:01 +00:00
069dfc0ae4 fix: Windows-safe DB_PATH via env var, add Windows installer scripts 2026-03-07 13:43:35 +01:00
13 changed files with 2399 additions and 988 deletions

66
.github/workflows/build-windows.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: BatchTube Windows Build
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version tag (e.g. v1.0.0)'
required: false
default: 'v1.0.0'
jobs:
build-windows:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
cd backend
pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller
- name: Download yt-dlp.exe
run: |
mkdir -p tools
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe -o tools/yt-dlp.exe
- name: Create empty database
run: |
cd backend
python -c "import sqlite3; sqlite3.connect('youtube_sipoc.db').close()"
- name: Build Windows EXE
run: |
cd backend
pyinstaller batchtube-windows.spec --clean --noconfirm
- name: Install NSIS
run: choco install nsis -y
- name: Build NSIS Installer
run: makensis installer.nsi
- name: Upload EXE artifact
uses: actions/upload-artifact@v4
with:
name: BatchTube-Windows-EXE
path: backend/dist/BatchTube.exe
retention-days: 30
- name: Upload Installer artifact
uses: actions/upload-artifact@v4
with:
name: BatchTube-Windows-Installer
path: BatchTube-Setup-*.exe
retention-days: 30

116
WINDOWS_BUILD_README.md Normal file
View File

@@ -0,0 +1,116 @@
# BatchTube Windows Build Guide
Intentures LLC | https://batchtube.com | v1.0.0
## Files In This Package
| File | Location | Purpose |
|------|----------|---------|
| batchtube-launcher.py | backend/ | Windows entry point - starts FastAPI + opens browser |
| batchtube-windows.spec | backend/ | PyInstaller spec - single-file EXE with all deps |
| version_info.txt | backend/ | Windows EXE metadata |
| installer.nsi | project root | NSIS installer script |
| build_windows.bat | project root | One-click build script |
## Prerequisites
- Python 3.11+ (64-bit) - https://python.org/downloads
- NSIS 3.x - https://nsis.sourceforge.io/
- Git - https://git-scm.com
## Quick Build
Double-click build_windows.bat - it handles everything:
1. Creates virtual environment
2. Installs all Python dependencies
3. Downloads yt-dlp.exe
4. Runs PyInstaller -> backend/dist/BatchTube.exe
5. Runs NSIS -> BatchTube-Setup-1.0.0.exe
## Manual Build Steps
### Step 1 - Get Source
scp -r root@212.28.188.26:/root/batchtube-tauri ./batchtube
cd batchtube
### Step 2 - Fix config.py DB Path
Edit backend/config.py - replace the DB_PATH line:
# Before:
DB_PATH = os.path.join(os.path.dirname(__file__), "youtube_sipoc.db")
# After:
DB_PATH = os.environ.get(
'BATCHTUBE_DB_PATH',
os.path.join(os.path.dirname(__file__), "youtube_sipoc.db")
)
### Step 3 - Install Dependencies
cd backend
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
pip install pyinstaller
### Step 4 - Download yt-dlp
mkdir ..\tools
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe -o ..\tools\yt-dlp.exe
### Step 5 - Build EXE
pyinstaller batchtube-windows.spec --clean
# Output: backend/dist/BatchTube.exe
### Step 6 - Test EXE
dist\BatchTube.exe
# Browser should open to http://127.0.0.1:8765
### Step 7 - Build Installer
cd ..
makensis installer.nsi
# Output: BatchTube-Setup-1.0.0.exe
## Troubleshooting
| Problem | Fix |
|---------|-----|
| ModuleNotFoundError at runtime | Add to hiddenimports in batchtube-windows.spec |
| Web UI 404 | Check datas path ('web','backend/web') in spec |
| DB crash on launch | Apply config.py DB_PATH fix in Step 2 |
| App closes instantly | Set console=True in spec temporarily to see errors |
| SmartScreen warning | Code-sign BatchTube.exe with a Windows cert |
## After Install
| Path | Contents |
|------|----------|
| C:\Program Files\BatchTube\BatchTube.exe | Application |
| %APPDATA%\BatchTube\batchtube.db | SQLite database |
| Start Menu -> BatchTube | Launch shortcut |
| Desktop | Launch shortcut |
## GitHub Actions - Automated Windows Build
Add to .github/workflows/build.yml:
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.11' }
- run: pip install -r backend/requirements.txt pyinstaller
- run: cd backend && pyinstaller batchtube-windows.spec --clean
- run: choco install nsis -y && makensis installer.nsi
- uses: actions/upload-artifact@v4
with:
name: BatchTube-Windows
path: BatchTube-Setup-*.exe
---
Generated 2026-03-07 by Agent Developer - Intentures LLC

View File

@@ -118,6 +118,40 @@ async def create_job(req: CreateJobRequest):
if not req.input_value.strip(): if not req.input_value.strip():
raise HTTPException(status_code=400, detail="input_value is required") raise HTTPException(status_code=400, detail="input_value is required")
# ── Free Tier Enforcement ─────────────────────────────────────────────────
plan = config.BATCHTUBE_PLAN
limits = config.PLAN_LIMITS.get(plan, config.PLAN_LIMITS["free"])
# Cap resolution for free tier
resolution = req.resolution
max_res = limits.get("max_resolution")
if max_res and max_res != "best":
res_order = config.AVAILABLE_RESOLUTIONS # ["best", "4320", ..., "144"]
# Lower index = higher quality; cap if requested res is higher than allowed
def res_index(r):
try:
return res_order.index(r)
except ValueError:
return len(res_order)
if res_index(resolution) < res_index(max_res):
logger.info(f"Free tier: capping resolution from {resolution} to {max_res}")
resolution = max_res
else:
resolution = req.resolution
# For CSV input: enforce max_videos limit upfront
max_videos = limits.get("max_videos")
if max_videos is not None and req.input_type == "csv":
csv_lines = [ln.strip() for ln in req.input_value.strip().splitlines() if ln.strip()]
if len(csv_lines) > max_videos:
raise HTTPException(
status_code=403,
detail=f"Free tier is limited to {max_videos} videos per batch. "
f"Upgrade to Creator or Pro for larger batches. "
f"({len(csv_lines)} URLs submitted)"
)
# Create the folder if it doesn't exist # Create the folder if it doesn't exist
try: try:
Path(output_folder).mkdir(parents=True, exist_ok=True) Path(output_folder).mkdir(parents=True, exist_ok=True)
@@ -128,7 +162,7 @@ async def create_job(req: CreateJobRequest):
job_id = db.create_job( job_id = db.create_job(
output_folder=output_folder, output_folder=output_folder,
selections=req.selections, selections=req.selections,
resolution=req.resolution, resolution=resolution, # may be capped by free tier enforcement
delay_min=req.delay_min, delay_min=req.delay_min,
delay_max=req.delay_max, delay_max=req.delay_max,
input_type=req.input_type, input_type=req.input_type,

View File

@@ -0,0 +1,34 @@
import sys, os, time, socket, threading, webbrowser
if getattr(sys, 'frozen', False):
BASE_DIR = sys._MEIPASS
APP_DIR = os.path.dirname(sys.executable)
else:
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
APP_DIR = BASE_DIR
BACKEND_DIR = os.path.join(BASE_DIR,'backend') if os.path.isdir(os.path.join(BASE_DIR,'backend')) else BASE_DIR
sys.path.insert(0, BACKEND_DIR)
sys.path.insert(0, BASE_DIR)
APPDATA_DIR = os.path.join(os.environ.get('APPDATA', APP_DIR), 'BatchTube')
os.makedirs(APPDATA_DIR, exist_ok=True)
os.environ['BATCHTUBE_DB_PATH'] = os.path.join(APPDATA_DIR, 'batchtube.db')
for c in [os.path.join(APP_DIR,'yt-dlp.exe'), os.path.join(BASE_DIR,'yt-dlp.exe')]:
if os.path.exists(c): os.environ['YTDLP_PATH'] = c; break
for d in [os.path.join(APP_DIR,'ffmpeg'), os.path.join(BASE_DIR,'ffmpeg')]:
if os.path.isdir(d): os.environ['PATH'] = d + os.pathsep + os.environ.get('PATH',''); break
HOST, PORT = '127.0.0.1', 8765
URL = f'http://{HOST}:{PORT}'
def is_open(h, p, t=0.5):
try:
with socket.create_connection((h,p), timeout=t): return True
except: return False
def open_browser():
for _ in range(60):
if is_open(HOST, PORT): time.sleep(0.3); webbrowser.open(URL); return
time.sleep(0.5)
def run_server():
import uvicorn
os.chdir(BACKEND_DIR)
uvicorn.run('api_server:app', host=HOST, port=PORT, log_level='warning', access_log=False)
if __name__ == '__main__':
threading.Thread(target=open_browser, daemon=True).start()
run_server()

View File

@@ -0,0 +1,54 @@
# batchtube-windows.spec
# PyInstaller spec for Windows single-file EXE
# Run from backend/ directory: pyinstaller batchtube-windows.spec --clean
# Output: dist/BatchTube.exe
from PyInstaller.utils.hooks import collect_all
block_cipher = None
datas, binaries, hiddenimports = [], [], []
for pkg in ['yt_dlp','uvicorn','fastapi','starlette','anyio','sse_starlette','youtube_transcript_api','openai','pydantic']:
d,b,h = collect_all(pkg)
datas+=d; binaries+=b; hiddenimports+=h
datas += [('web','backend/web')]
hiddenimports += [
'uvicorn.logging','uvicorn.loops','uvicorn.loops.auto','uvicorn.loops.asyncio',
'uvicorn.protocols','uvicorn.protocols.http','uvicorn.protocols.http.auto',
'uvicorn.protocols.http.h11_impl','uvicorn.protocols.http.httptools_impl',
'uvicorn.protocols.websockets','uvicorn.protocols.websockets.auto',
'uvicorn.lifespan','uvicorn.lifespan.off','uvicorn.lifespan.on',
'fastapi','fastapi.middleware.cors','starlette.middleware.cors',
'sse_starlette','sse_starlette.sse',
'pydantic','pydantic.v1','pydantic_core','annotated_types','typing_extensions',
'h11','httptools','httpx','anyio','anyio._backends._asyncio','sniffio',
'multipart','python_multipart','aiofiles','aiofiles.os','aiofiles.threadpool',
'yt_dlp','yt_dlp.extractor','yt_dlp.downloader','yt_dlp.postprocessor',
'youtube_transcript_api','youtube_transcript_api._transcripts',
'openai','openai.resources',
'requests','urllib3','certifi','charset_normalizer',
'slugify','python_slugify','tqdm','tqdm.auto',
'sqlite3','_sqlite3','asyncio','concurrent.futures','threading','queue',
'websockets','click','rich','watchfiles','mcp',
'api_server','worker','database','extractors','config',
]
a = Analysis(
['batchtube-launcher.py'],
pathex=['.'],
binaries=binaries,
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
runtime_hooks=[],
excludes=['tkinter','matplotlib','numpy','pandas','torch','tensorflow','PyQt5','PyQt6'],
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [],
name='BatchTube',
debug=False, strip=False, upx=True,
runtime_tmpdir=None,
console=False,
icon='../src-tauri/icons/icon.ico',
version='version_info.txt',
)

View File

@@ -1,5 +1,5 @@
""" """
config.py - Default configuration for YouTube SIPOC Tool config.py - Default configuration for BatchTube
""" """
import os import os
@@ -32,7 +32,40 @@ SUMMARY_MAX_TOKENS = 1024
MAX_TITLE_LENGTH = 80 # characters - truncate long titles in filenames MAX_TITLE_LENGTH = 80 # characters - truncate long titles in filenames
# ── Database ────────────────────────────────────────────────────────────────── # ── Database ──────────────────────────────────────────────────────────────────
DB_PATH = os.path.join(os.path.dirname(__file__), "youtube_sipoc.db") # Windows-safe: allow override via env var (avoids path issues in PyInstaller bundles)
DB_PATH = os.environ.get(
"BATCHTUBE_DB_PATH",
os.path.join(os.path.dirname(__file__), "youtube_sipoc.db")
)
# ── Artifact Types ──────────────────────────────────────────────────────────── # ── Artifact Types ────────────────────────────────────────────────────────────
ARTIFACT_TYPES = ["title", "stats", "transcript", "summary", "thumbnail", "mp3", "mp4"] ARTIFACT_TYPES = ["title", "stats", "transcript", "summary", "thumbnail", "mp3", "mp4"]
# ── Licensing / Plan Tiers ────────────────────────────────────────────────────
# Plan is set via environment variable BATCHTUBE_PLAN.
# Valid values: free | creator | pro | studio | lifetime
# Defaults to 'free' — license validation layer overrides this at runtime.
BATCHTUBE_PLAN = os.environ.get("BATCHTUBE_PLAN", "free").lower()
# ── Free Tier Limits (updated 2026-03-07) ─────────────────────────────────────
# Free tier: 3 videos/batch max (tightened from 5), 720p max resolution
FREE_TIER_MAX_VIDEOS = 3 # max videos per batch job on free plan
FREE_TIER_MAX_RESOLUTION = "720" # max resolution on free plan (was 1080p)
# ── Plan Limits Map ───────────────────────────────────────────────────────────
# Maps plan name -> {max_videos, max_resolution}; None = unlimited
PLAN_LIMITS = {
"free": {"max_videos": FREE_TIER_MAX_VIDEOS, "max_resolution": FREE_TIER_MAX_RESOLUTION},
"creator": {"max_videos": 100, "max_resolution": "1080"},
"pro": {"max_videos": None, "max_resolution": "best"},
"studio": {"max_videos": None, "max_resolution": "best"},
"lifetime": {"max_videos": None, "max_resolution": "best"},
}
# ── Pricing Reference (2026-03-07 approved) ───────────────────────────────────
# Free: 3 videos/batch, 720p max
# Creator: $19/mo or $149/yr — 100 videos/batch, 1080p
# Pro: $39/mo or $299/yr — unlimited, 4K
# Studio: $79/mo — 3 seats, API access
# Lifetime: $197 one-time — unlimited, all features
# AppSumo: $79 one-time — limited launch deal

16
backend/version_info.txt Normal file
View File

@@ -0,0 +1,16 @@
VSVersionInfo(
ffi=FixedFileInfo(filevers=(1,0,0,0),prodvers=(1,0,0,0),mask=0x3f,flags=0x0,OS=0x40004,fileType=0x1,subtype=0x0,date=(0,0)),
kids=[
StringFileInfo([StringTable(u'040904B0',[
StringStruct(u'CompanyName',u'Intentures LLC'),
StringStruct(u'FileDescription',u'BatchTube - Batch YouTube Content Extractor'),
StringStruct(u'FileVersion',u'1.0.0.0'),
StringStruct(u'InternalName',u'BatchTube'),
StringStruct(u'LegalCopyright',u'Copyright (C) 2026 Intentures LLC'),
StringStruct(u'OriginalFilename',u'BatchTube.exe'),
StringStruct(u'ProductName',u'BatchTube'),
StringStruct(u'ProductVersion',u'1.0.0.0'),
])]),
VarFileInfo([VarStruct(u'Translation',[1033,1200])])
]
)

View File

@@ -171,6 +171,27 @@ def run_job(job_id: str):
unique_videos.append(v) unique_videos.append(v)
videos = unique_videos videos = unique_videos
# ── Free Tier: Enforce max videos per batch ───────────────────────────
plan = config.BATCHTUBE_PLAN
limits = config.PLAN_LIMITS.get(plan, config.PLAN_LIMITS["free"])
max_videos = limits.get("max_videos")
if max_videos is not None and len(videos) > max_videos:
db.add_log(
job_id,
f"Free tier limit: truncating batch from {len(videos)} to {max_videos} videos. "
f"Upgrade to Creator or Pro for larger batches.",
level="WARN"
)
_emit(job_id, "tier_limit", {
"job_id": job_id,
"plan": plan,
"requested": len(videos),
"allowed": max_videos,
"message": f"Free tier: batch limited to {max_videos} videos. Upgrade for more."
})
videos = videos[:max_videos]
# ── Step 2: Register videos in DB ──────────────────────────────────── # ── Step 2: Register videos in DB ────────────────────────────────────
for i, v in enumerate(videos): for i, v in enumerate(videos):
db.upsert_video(job_id, v["video_id"], v["url"], v.get("title", ""), i) db.upsert_video(job_id, v["video_id"], v["url"], v.get("title", ""), i)

45
build_windows.bat Normal file
View File

@@ -0,0 +1,45 @@
@echo off
title BatchTube Windows Build
echo.
echo ============================================================
echo BatchTube Windows Installer Builder v1.0.0
echo Intentures LLC - https://batchtube.com
echo ============================================================
echo.
python --version >nul 2>&1
if errorlevel 1 (echo ERROR: Python not found. Install Python 3.11+ && pause && exit /b 1)
echo [1/5] Creating virtual environment...
if exist build_venv rmdir /s /q build_venv
python -m venv build_venv
call build_venv\Scripts\activate.bat
echo [2/5] Installing dependencies...
pip install --upgrade pip -q
pip install -r backend\requirements.txt -q
pip install pyinstaller -q
echo [3/5] Downloading yt-dlp...
if not exist tools mkdir tools
curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe -o tools\yt-dlp.exe
echo [4/5] Building with PyInstaller...
cd backend
pyinstaller batchtube-windows.spec --clean --noconfirm
cd ..
if not exist backend\dist\BatchTube.exe (echo ERROR: Build failed && pause && exit /b 1)
echo Build successful: backend\dist\BatchTube.exe
echo [5/5] Creating NSIS installer...
makensis /VERSION >nul 2>&1
if errorlevel 1 (
echo NSIS not found - install from https://nsis.sourceforge.io/
echo Your EXE is ready at: backend\dist\BatchTube.exe
) else (
makensis installer.nsi
echo.
echo SUCCESS: BatchTube-Setup-1.0.0.exe created
)
pause

11
deploy-web.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
# BatchTube Landing Page Deploy Script
# Run on server: bash deploy-web.sh
set -e
SRC_DIR="$(dirname "$0")/web"
DEST_DIR="/opt/www/batchtube"
echo "Deploying BatchTube landing page..."
cp "$SRC_DIR/index.html" "$DEST_DIR/index.html"
cp "$SRC_DIR/affiliates.html" "$DEST_DIR/affiliates.html"
echo "✅ Deploy complete: $DEST_DIR"
ls -lh "$DEST_DIR"

61
installer.nsi Normal file
View File

@@ -0,0 +1,61 @@
; BatchTube NSIS Installer Script - Updated for backend/ structure
; Requires NSIS 3.x - https://nsis.sourceforge.io/
!define APP_NAME "BatchTube"
!define APP_VERSION "1.0.0"
!define APP_PUBLISHER "Intentures LLC"
!define APP_URL "https://batchtube.com"
!define APP_EXE "BatchTube.exe"
!define INSTALL_DIR "$PROGRAMFILES64\BatchTube"
Name "${APP_NAME} ${APP_VERSION}"
OutFile "BatchTube-Setup-${APP_VERSION}.exe"
InstallDir "${INSTALL_DIR}"
InstallDirRegKey HKLM "Software\${APP_NAME}" "Install_Dir"
RequestExecutionLevel admin
!include "MUI2.nsh"
!define MUI_ABORTWARNING
!define MUI_ICON "..\src-tauri\icons\icon.ico"
!define MUI_UNICON "..\src-tauri\icons\icon.ico"
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "..\LICENSE.txt"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_RUN "$INSTDIR\${APP_EXE}"
!define MUI_FINISHPAGE_RUN_TEXT "Launch BatchTube now"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
Section "BatchTube" SecMain
SetOutPath "$INSTDIR"
File "backend\dist\BatchTube.exe"
; Optional: bundle yt-dlp
; File "tools\yt-dlp.exe"
; Optional: bundle ffmpeg
; File /r "tools\ffmpeg"
WriteRegStr HKLM "Software\${APP_NAME}" "Install_Dir" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "DisplayName" "${APP_NAME}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "UninstallString" '"$INSTDIR\Uninstall.exe"'
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "DisplayVersion" "${APP_VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "Publisher" "${APP_PUBLISHER}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "URLInfoAbout" "${APP_URL}"
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}" "NoRepair" 1
WriteUninstaller "$INSTDIR\Uninstall.exe"
CreateShortcut "$DESKTOP\BatchTube.lnk" "$INSTDIR\${APP_EXE}"
CreateDirectory "$SMPROGRAMS\BatchTube"
CreateShortcut "$SMPROGRAMS\BatchTube\BatchTube.lnk" "$INSTDIR\${APP_EXE}"
CreateShortcut "$SMPROGRAMS\BatchTube\Uninstall BatchTube.lnk" "$INSTDIR\Uninstall.exe"
SectionEnd
Section "Uninstall"
RMDir /r "$INSTDIR"
Delete "$DESKTOP\BatchTube.lnk"
RMDir /r "$SMPROGRAMS\BatchTube"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_NAME}"
DeleteRegKey HKLM "Software\${APP_NAME}"
SectionEnd

359
web/affiliates.html Normal file
View File

@@ -0,0 +1,359 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>BatchTube Affiliate Program — Earn 30% Commission</title>
<meta name="description" content="Join the BatchTube affiliate program and earn 30% commission on every sale — monthly, annual, and lifetime plans. Managed via ThriveCart." />
<style>
:root {
--orange: #ff8822;
--orange2: #cc5500;
--dark: #0f0f0f;
--dark2: #1a1a1a;
--dark3: #242424;
--border: #2e2e2e;
--text: #f0f0f0;
--text-dim: #aaa;
--radius: 10px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Segoe UI', system-ui, sans-serif; background: var(--dark); color: var(--text); line-height: 1.6; }
a { color: var(--orange); text-decoration: none; }
a:hover { text-decoration: underline; }
/* NAV */
nav { display: flex; align-items: center; justify-content: space-between; padding: 16px 40px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: rgba(15,15,15,0.95); backdrop-filter: blur(8px); z-index: 100; }
.nav-logo { font-size: 22px; font-weight: 800; color: var(--text); }
.nav-logo span { color: var(--orange); }
.nav-links { display: flex; gap: 28px; font-size: 14px; }
.nav-links a { color: var(--text-dim); transition: color 0.2s; }
.nav-links a:hover, .nav-links a.active { color: var(--text); text-decoration: none; }
.nav-cta { background: var(--orange); color: #fff; padding: 10px 20px; border-radius: 8px; font-size: 14px; font-weight: 700; transition: background 0.2s; }
.nav-cta:hover { background: var(--orange2); text-decoration: none; }
/* HERO */
.aff-hero { text-align: center; padding: 80px 20px 60px; background: linear-gradient(180deg, rgba(255,136,34,0.06) 0%, transparent 100%); }
.aff-badge { display: inline-block; background: rgba(255,136,34,0.15); border: 1px solid rgba(255,136,34,0.3); color: var(--orange); font-size: 12px; font-weight: 700; padding: 6px 16px; border-radius: 20px; margin-bottom: 24px; letter-spacing: 1px; text-transform: uppercase; }
.aff-hero h1 { font-size: clamp(32px, 5vw, 60px); font-weight: 800; margin-bottom: 20px; line-height: 1.1; }
.aff-hero h1 span { color: var(--orange); }
.aff-hero p { font-size: 18px; color: var(--text-dim); max-width: 600px; margin: 0 auto 40px; }
.btn-primary { display: inline-block; background: var(--orange); color: #fff; padding: 16px 36px; border-radius: 10px; font-size: 16px; font-weight: 700; transition: background 0.2s; }
.btn-primary:hover { background: var(--orange2); text-decoration: none; }
.btn-outline { display: inline-block; border: 2px solid var(--border); color: var(--text); padding: 14px 32px; border-radius: 10px; font-size: 15px; font-weight: 600; transition: all 0.2s; margin-left: 12px; }
.btn-outline:hover { border-color: var(--orange); color: var(--orange); text-decoration: none; }
/* STATS BAR */
.stats-bar { display: flex; justify-content: center; gap: 60px; padding: 40px 20px; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); background: var(--dark2); flex-wrap: wrap; }
.stat-item { text-align: center; }
.stat-num { font-size: 36px; font-weight: 800; color: var(--orange); }
.stat-label { font-size: 13px; color: var(--text-dim); margin-top: 4px; }
/* SECTION */
.section { max-width: 1100px; margin: 0 auto; padding: 80px 20px; }
.section-label { font-size: 12px; font-weight: 700; letter-spacing: 2px; text-transform: uppercase; color: var(--orange); margin-bottom: 12px; }
.section-title { font-size: clamp(26px, 3.5vw, 40px); font-weight: 800; margin-bottom: 16px; }
.section-sub { font-size: 17px; color: var(--text-dim); max-width: 600px; margin-bottom: 48px; }
/* HOW IT WORKS */
.steps-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 24px; }
.step-card { background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; }
.step-num { width: 40px; height: 40px; background: var(--orange); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; font-weight: 800; margin-bottom: 16px; }
.step-title { font-size: 16px; font-weight: 700; margin-bottom: 8px; }
.step-desc { font-size: 14px; color: var(--text-dim); line-height: 1.6; }
/* COMMISSION TABLE */
.commission-table { width: 100%; border-collapse: collapse; margin-bottom: 32px; }
.commission-table th { background: var(--dark3); padding: 14px 20px; text-align: left; font-size: 13px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-dim); border-bottom: 1px solid var(--border); }
.commission-table td { padding: 16px 20px; border-bottom: 1px solid var(--border); font-size: 15px; }
.commission-table tr:hover td { background: rgba(255,136,34,0.03); }
.commission-table .earn { color: var(--orange); font-weight: 700; font-size: 16px; }
.commission-table .featured-row td { background: rgba(255,136,34,0.05); }
/* CALCULATOR */
.calculator { background: var(--dark2); border: 1px solid var(--orange); border-radius: var(--radius); padding: 40px; max-width: 700px; margin: 0 auto; }
.calculator h3 { font-size: 22px; font-weight: 800; margin-bottom: 8px; }
.calculator p { color: var(--text-dim); font-size: 14px; margin-bottom: 28px; }
.calc-row { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
.calc-label { font-size: 14px; font-weight: 600; min-width: 160px; }
.calc-input { background: var(--dark3); border: 1px solid var(--border); color: var(--text); padding: 10px 16px; border-radius: 8px; font-size: 16px; width: 120px; }
.calc-input:focus { outline: none; border-color: var(--orange); }
select.calc-input { width: 180px; cursor: pointer; }
.calc-result { background: linear-gradient(135deg, rgba(255,136,34,0.15), rgba(255,136,34,0.05)); border: 1px solid rgba(255,136,34,0.3); border-radius: var(--radius); padding: 24px 32px; text-align: center; margin-top: 24px; }
.calc-result .monthly-earn { font-size: 42px; font-weight: 800; color: var(--orange); }
.calc-result .annual-earn { font-size: 20px; color: var(--text-dim); margin-top: 4px; }
.calc-result .label { font-size: 13px; color: var(--text-dim); margin-top: 8px; }
/* PAYOUTS */
.payout-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; }
.payout-card { background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); padding: 24px; text-align: center; }
.payout-icon { font-size: 32px; margin-bottom: 12px; }
.payout-title { font-size: 15px; font-weight: 700; margin-bottom: 6px; }
.payout-desc { font-size: 13px; color: var(--text-dim); }
/* CTA */
.aff-cta { text-align: center; padding: 80px 20px; background: linear-gradient(180deg, transparent, rgba(255,136,34,0.06)); }
.aff-cta h2 { font-size: clamp(28px, 4vw, 44px); font-weight: 800; margin-bottom: 16px; }
.aff-cta p { font-size: 17px; color: var(--text-dim); max-width: 520px; margin: 0 auto 36px; }
/* FOOTER */
footer { text-align: center; padding: 40px 20px; border-top: 1px solid var(--border); color: var(--text-dim); font-size: 14px; }
.footer-logo { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 12px; }
.footer-logo span { color: var(--orange); }
@media (max-width: 600px) {
nav { padding: 14px 20px; }
.nav-links { display: none; }
.stats-bar { gap: 30px; }
.calc-row { flex-direction: column; align-items: flex-start; }
}
</style>
</head>
<body>
<!-- NAV -->
<nav>
<div class="nav-logo">Batch<span>Tube</span></div>
<div class="nav-links">
<a href="/#features">Features</a>
<a href="/#pricing">Pricing</a>
<a href="/affiliates.html" class="active">Affiliates</a>
<a href="/#faq">FAQ</a>
</div>
<a href="https://qmg.thrivecart.com/affiliate/request-access/batchtube/" class="nav-cta" target="_blank">Join Now &rarr;</a>
</nav>
<!-- HERO -->
<div class="aff-hero">
<div class="aff-badge">&#128176; Affiliate Program</div>
<h1>Earn <span>30% Commission</span><br>On Every BatchTube Sale</h1>
<p>Monthly subscriptions. Annual plans. Lifetime deals. You refer once — we pay you every renewal. No cap. No expiry.</p>
<a href="https://qmg.thrivecart.com/affiliate/request-access/batchtube/" class="btn-primary" target="_blank">Apply to Become an Affiliate &rarr;</a>
<a href="#calculator" class="btn-outline">Calculate Your Earnings</a>
</div>
<!-- STATS BAR -->
<div class="stats-bar">
<div class="stat-item">
<div class="stat-num">30%</div>
<div class="stat-label">Commission Rate</div>
</div>
<div class="stat-item">
<div class="stat-num">$59</div>
<div class="stat-label">Max Per Lifetime Sale</div>
</div>
<div class="stat-item">
<div class="stat-num">30 days</div>
<div class="stat-label">Cookie Duration</div>
</div>
<div class="stat-item">
<div class="stat-num">Instant</div>
<div class="stat-label">ThriveCart Tracking</div>
</div>
<div class="stat-item">
<div class="stat-num">Monthly</div>
<div class="stat-label">Payout Schedule</div>
</div>
</div>
<!-- HOW IT WORKS -->
<section class="section">
<div class="section-label">How It Works</div>
<h2 class="section-title">Simple. Transparent. Profitable.</h2>
<p class="section-sub">Four steps from signup to your first commission check.</p>
<div class="steps-grid">
<div class="step-card">
<div class="step-num">1</div>
<div class="step-title">Apply</div>
<div class="step-desc">Submit your affiliate application via ThriveCart. Approval is fast — usually within 24 hours.</div>
</div>
<div class="step-card">
<div class="step-num">2</div>
<div class="step-title">Get Your Link</div>
<div class="step-desc">Receive your unique tracking link. Share it on YouTube, blogs, newsletters, social media — anywhere your audience lives.</div>
</div>
<div class="step-card">
<div class="step-num">3</div>
<div class="step-title">Refer &amp; Earn</div>
<div class="step-desc">Every time someone buys through your link, you earn 30% commission. Monthly plans pay every renewal cycle.</div>
</div>
<div class="step-card">
<div class="step-num">4</div>
<div class="step-title">Get Paid</div>
<div class="step-desc">Commissions paid monthly via PayPal or bank transfer through ThriveCart's affiliate payout system.</div>
</div>
</div>
</section>
<!-- COMMISSION TABLE -->
<section class="section" style="padding-top:0;">
<div class="section-label">Commission Breakdown</div>
<h2 class="section-title">What You Earn Per Sale</h2>
<p class="section-sub">30% on every plan — monthly, annual, and lifetime.</p>
<table class="commission-table">
<thead>
<tr>
<th>Plan</th>
<th>Price</th>
<th>Your Commission</th>
<th>Annual Earnings (10 sales/mo)</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Creator Monthly</strong></td>
<td>$19/mo</td>
<td class="earn">$5.70/mo per customer</td>
<td>$684/yr</td>
</tr>
<tr>
<td><strong>Creator Annual</strong></td>
<td>$190/yr</td>
<td class="earn">$57 per sale</td>
<td>$570/yr</td>
</tr>
<tr class="featured-row">
<td><strong>Pro Monthly</strong></td>
<td>$39/mo</td>
<td class="earn">$11.70/mo per customer</td>
<td>$1,404/yr</td>
</tr>
<tr class="featured-row">
<td><strong>Pro Annual</strong></td>
<td>$790/yr</td>
<td class="earn">$237 per sale</td>
<td>$2,370/yr</td>
</tr>
<tr>
<td><strong>Studio Monthly</strong></td>
<td>$79/mo</td>
<td class="earn">$23.70/mo per customer</td>
<td>$2,844/yr</td>
</tr>
<tr>
<td><strong>Studio Annual</strong></td>
<td>$790/yr</td>
<td class="earn">$237 per sale</td>
<td>$2,370/yr</td>
</tr>
<tr style="border-top: 2px solid var(--orange);">
<td><strong>&#128293; Lifetime</strong></td>
<td>$197 &ndash; $247</td>
<td class="earn">$59.10 &ndash; $74.10 once</td>
<td>$591 &ndash; $741 (10 sales)</td>
</tr>
</tbody>
</table>
<p style="font-size:13px; color:var(--text-dim);">* Monthly plan commissions recur every billing cycle as long as the customer remains subscribed.</p>
</section>
<!-- CALCULATOR -->
<section class="section" id="calculator" style="padding-top:0;">
<div class="section-label">Earnings Calculator</div>
<h2 class="section-title">How Much Can You Make?</h2>
<p class="section-sub">Plug in your numbers. See your potential.</p>
<div class="calculator">
<h3>&#129518; Commission Calculator</h3>
<p>Estimate your monthly and annual affiliate earnings</p>
<div class="calc-row">
<span class="calc-label">Plan type:</span>
<select class="calc-input" id="calc-plan" onchange="calcEarnings()">
<option value="19">Creator Monthly ($19/mo)</option>
<option value="190" data-type="annual">Creator Annual ($190)</option>
<option value="39" selected>Pro Monthly ($39/mo)</option>
<option value="790" data-type="annual">Pro Annual ($790)</option>
<option value="79">Studio Monthly ($79/mo)</option>
<option value="790" data-type="annual">Studio Annual ($790)</option>
<option value="197" data-type="lifetime">Lifetime ($197)</option>
</select>
</div>
<div class="calc-row">
<span class="calc-label">Referrals per month:</span>
<input type="number" class="calc-input" id="calc-refs" value="10" min="1" max="10000" oninput="calcEarnings()" />
</div>
<div class="calc-result" id="calc-result">
<div class="monthly-earn" id="monthly-earn">$117.00</div>
<div class="annual-earn" id="annual-earn">$1,404.00 / year</div>
<div class="label">Estimated affiliate earnings at 30% commission</div>
</div>
</div>
</section>
<!-- PAYOUT INFO -->
<section class="section" style="padding-top:0;">
<div class="section-label">Payouts</div>
<h2 class="section-title">Getting Paid Is Easy</h2>
<p class="section-sub">ThriveCart handles all tracking, attribution, and payouts automatically.</p>
<div class="payout-grid">
<div class="payout-card">
<div class="payout-icon">&#128197;</div>
<div class="payout-title">Monthly Payouts</div>
<div class="payout-desc">Commissions paid out monthly. No waiting 90 days.</div>
</div>
<div class="payout-card">
<div class="payout-icon">&#128279;</div>
<div class="payout-title">30-Day Cookie</div>
<div class="payout-desc">Visitors tracked for 30 days after clicking your link.</div>
</div>
<div class="payout-card">
<div class="payout-icon">&#128202;</div>
<div class="payout-title">Real-Time Dashboard</div>
<div class="payout-desc">Track clicks, conversions, and earnings live in ThriveCart.</div>
</div>
<div class="payout-card">
<div class="payout-icon">&#128176;</div>
<div class="payout-title">Recurring Revenue</div>
<div class="payout-desc">Monthly subscribers pay you every single month they stay.</div>
</div>
</div>
</section>
<!-- CTA -->
<div class="aff-cta">
<h2>Ready to Start Earning?</h2>
<p>Join the BatchTube affiliate program today. Free to join. No approval wait. Start earning 30% on day one.</p>
<a href="https://qmg.thrivecart.com/affiliate/request-access/batchtube/" class="btn-primary" target="_blank">Apply Now — It's Free &rarr;</a>
</div>
<!-- FOOTER -->
<footer>
<div class="footer-logo">Batch<span>Tube</span></div>
<p style="margin-bottom:12px;">Built by <a href="https://intentures.org">Intentures LLC</a> &bull; <a href="https://mautic.intentures.org/form/1" target="_blank" rel="noopener">Contact Us</a></p>
<p>&copy; 2026 Intentures LLC. All rights reserved.</p>
</footer>
<script>
function calcEarnings() {
const planSelect = document.getElementById('calc-plan');
const refs = parseInt(document.getElementById('calc-refs').value) || 0;
const price = parseFloat(planSelect.value);
const selectedOption = planSelect.options[planSelect.selectedIndex];
const type = selectedOption.getAttribute('data-type') || 'monthly';
const commission = price * 0.30;
let monthlyEarn, annualEarn;
if (type === 'lifetime') {
monthlyEarn = commission * refs;
annualEarn = monthlyEarn; // one-time
document.getElementById('annual-earn').textContent = 'One-time commissions';
} else if (type === 'annual') {
monthlyEarn = commission * refs;
annualEarn = monthlyEarn; // annual sales per month
document.getElementById('annual-earn').textContent = '$' + (annualEarn * 12).toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2}) + ' / year';
} else {
// monthly recurring
monthlyEarn = commission * refs;
annualEarn = monthlyEarn * 12;
document.getElementById('annual-earn').textContent = '$' + annualEarn.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2}) + ' / year';
}
document.getElementById('monthly-earn').textContent = '$' + monthlyEarn.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2});
}
// Init
calcEarnings();
</script>
</body>
</html>

561
web/index.html Normal file
View File

@@ -0,0 +1,561 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- SEO -->
<title>BatchTube — Bulk YouTube Downloader | Transcripts, MP3s &amp; AI Summaries</title>
<meta name="description" content="BatchTube batch downloads entire YouTube playlists, channels, and bulk URL lists — with transcripts, MP3 extraction, and AI summaries. Runs locally on Windows, Mac, and Linux. No cloud. No data leaks." />
<meta name="keywords" content="batch download YouTube, YouTube bulk downloader, YouTube playlist downloader, YouTube transcript extractor, YouTube MP3 extractor, bulk YouTube downloader, YouTube channel downloader" />
<!-- GEO -->
<meta name="geo.region" content="US" />
<meta name="geo.placename" content="United States" />
<link rel="alternate" hreflang="en-us" href="https://batchtube.com/" />
<link rel="alternate" hreflang="en-gb" href="https://batchtube.com/" />
<link rel="alternate" hreflang="en-ca" href="https://batchtube.com/" />
<link rel="alternate" hreflang="en-au" href="https://batchtube.com/" />
<link rel="alternate" hreflang="x-default" href="https://batchtube.com/" />
<!-- Open Graph -->
<meta property="og:title" content="BatchTube — Bulk YouTube Downloader" />
<meta property="og:description" content="Stop downloading one video at a time. BatchTube processes entire playlists, channels, and bulk URL lists with transcripts, MP3s, and AI summaries built in." />
<meta property="og:url" content="https://batchtube.com" />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://batchtube.com/og-image.png" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="BatchTube — Bulk YouTube Downloader" />
<meta name="twitter:description" content="Batch download YouTube videos, playlists, transcripts, MP3s and AI summaries. Runs locally. No cloud." />
<!-- Schema.org -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "BatchTube",
"applicationCategory": "UtilitiesApplication",
"operatingSystem": "Windows, macOS, Linux",
"offers": [
{"@type": "Offer", "name": "Free", "price": "0", "priceCurrency": "USD"},
{"@type": "Offer", "name": "Creator", "price": "19", "priceCurrency": "USD"},
{"@type": "Offer", "name": "Pro", "price": "39", "priceCurrency": "USD"},
{"@type": "Offer", "name": "Studio", "price": "79", "priceCurrency": "USD"},
{"@type": "Offer", "name": "Lifetime", "price": "197", "priceCurrency": "USD"}
],
"description": "BatchTube batch downloads entire YouTube playlists, channels, and bulk URL lists with transcripts, MP3 extraction, and AI summaries.",
"url": "https://batchtube.com"
}
</script>
<style>
:root {
--orange: #ff8822;
--orange2: #cc5500;
--dark: #0f0f0f;
--dark2: #1a1a1a;
--dark3: #242424;
--border: #2e2e2e;
--text: #f0f0f0;
--text-dim: #aaa;
--radius: 10px;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Segoe UI', system-ui, sans-serif; background: var(--dark); color: var(--text); line-height: 1.6; }
a { color: var(--orange); text-decoration: none; }
a:hover { text-decoration: underline; }
/* NAV */
nav { display: flex; align-items: center; justify-content: space-between; padding: 18px 40px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: rgba(15,15,15,0.95); backdrop-filter: blur(10px); z-index: 100; }
.nav-logo { display: flex; align-items: center; gap: 10px; font-size: 22px; font-weight: 700; color: var(--text); }
.nav-logo span { color: var(--orange); }
.nav-links { display: flex; gap: 28px; font-size: 14px; color: var(--text-dim); }
.nav-links a { color: var(--text-dim); }
.nav-links a:hover { color: var(--orange); text-decoration: none; }
.nav-cta { background: var(--orange); color: #fff; padding: 9px 22px; border-radius: 6px; font-weight: 600; font-size: 14px; }
.nav-cta:hover { background: var(--orange2); text-decoration: none; }
/* HERO */
.hero { text-align: center; padding: 100px 20px 80px; max-width: 860px; margin: 0 auto; }
.hero-badge { display: inline-block; background: rgba(255,136,34,0.15); color: var(--orange); border: 1px solid rgba(255,136,34,0.3); padding: 6px 16px; border-radius: 20px; font-size: 13px; font-weight: 600; margin-bottom: 28px; letter-spacing: 0.5px; }
.hero h1 { font-size: clamp(36px, 6vw, 64px); font-weight: 800; line-height: 1.1; margin-bottom: 24px; }
.hero h1 span { color: var(--orange); }
.hero p { font-size: 20px; color: var(--text-dim); max-width: 640px; margin: 0 auto 40px; }
.hero-btns { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
.btn-primary { background: var(--orange); color: #fff; padding: 16px 36px; border-radius: 8px; font-size: 17px; font-weight: 700; display: inline-block; transition: background 0.2s; }
.btn-primary:hover { background: var(--orange2); text-decoration: none; }
.btn-secondary { background: var(--dark3); color: var(--text); padding: 16px 36px; border-radius: 8px; font-size: 17px; font-weight: 600; border: 1px solid var(--border); display: inline-block; }
.btn-secondary:hover { border-color: var(--orange); color: var(--orange); text-decoration: none; }
.hero-sub { margin-top: 20px; font-size: 13px; color: var(--text-dim); }
.hero-stats { display: flex; gap: 40px; justify-content: center; margin-top: 48px; flex-wrap: wrap; }
.hero-stat { text-align: center; }
.hero-stat-num { font-size: 32px; font-weight: 800; color: var(--orange); }
.hero-stat-label { font-size: 13px; color: var(--text-dim); margin-top: 4px; }
/* DEMO */
.demo { max-width: 1000px; margin: 0 auto 80px; padding: 0 20px; }
.demo-window { background: var(--dark2); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.6); }
.demo-bar { background: var(--dark3); padding: 12px 16px; display: flex; align-items: center; gap: 8px; border-bottom: 1px solid var(--border); }
.demo-dot { width: 12px; height: 12px; border-radius: 50%; }
.demo-dot.red { background: #ff5f57; }
.demo-dot.yellow { background: #febc2e; }
.demo-dot.green { background: #28c840; }
.demo-title { flex: 1; text-align: center; font-size: 13px; color: var(--text-dim); }
.demo-body { padding: 32px; }
.demo-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }
.demo-stat-box { background: var(--dark3); border: 1px solid var(--border); border-radius: 8px; padding: 16px; text-align: center; }
.demo-stat-num { font-size: 28px; font-weight: 800; color: var(--orange); }
.demo-stat-label { font-size: 12px; color: var(--text-dim); margin-top: 4px; }
.demo-progress { background: var(--dark3); border: 1px solid var(--border); border-radius: 8px; padding: 16px; }
.demo-progress-label { font-size: 13px; color: var(--text-dim); margin-bottom: 10px; }
.demo-bar-track { background: var(--border); border-radius: 4px; height: 8px; overflow: hidden; }
.demo-bar-fill { background: linear-gradient(90deg, var(--orange), #ffaa44); height: 100%; border-radius: 4px; width: 73%; }
.demo-items { margin-top: 16px; display: flex; flex-direction: column; gap: 8px; }
.demo-item { display: flex; align-items: center; gap: 12px; font-size: 13px; color: var(--text-dim); }
.demo-item-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--orange); flex-shrink: 0; }
.demo-item-dot.done { background: #22cc66; }
.demo-item-dot.active { background: var(--orange); animation: pulse 1s infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
/* SECTIONS */
.section { max-width: 1100px; margin: 0 auto 80px; padding: 0 20px; }
.section-label { font-size: 13px; font-weight: 600; color: var(--orange); letter-spacing: 1px; text-transform: uppercase; margin-bottom: 12px; }
.section-title { font-size: clamp(28px, 4vw, 42px); font-weight: 800; margin-bottom: 16px; }
.section-sub { font-size: 18px; color: var(--text-dim); max-width: 600px; margin-bottom: 48px; }
/* FEATURES */
.features-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; }
.feature-card { background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; transition: border-color 0.2s; }
.feature-card:hover { border-color: var(--orange); }
.feature-icon { font-size: 28px; margin-bottom: 16px; }
.feature-title { font-size: 18px; font-weight: 700; margin-bottom: 8px; }
.feature-desc { font-size: 14px; color: var(--text-dim); line-height: 1.6; }
/* HOW IT WORKS */
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 32px; }
.step { text-align: center; }
.step-num { width: 48px; height: 48px; border-radius: 50%; background: rgba(255,136,34,0.15); border: 2px solid var(--orange); color: var(--orange); font-size: 20px; font-weight: 800; display: flex; align-items: center; justify-content: center; margin: 0 auto 16px; }
.step-title { font-size: 16px; font-weight: 700; margin-bottom: 8px; }
.step-desc { font-size: 14px; color: var(--text-dim); }
/* MID-PAGE CTA */
.mid-cta { background: linear-gradient(135deg, rgba(255,136,34,0.1), rgba(255,136,34,0.05)); border: 1px solid rgba(255,136,34,0.2); border-radius: 16px; padding: 60px 40px; text-align: center; max-width: 800px; margin: 0 auto 80px; }
.mid-cta h2 { font-size: clamp(24px, 4vw, 36px); font-weight: 800; margin-bottom: 16px; }
.mid-cta p { font-size: 18px; color: var(--text-dim); margin-bottom: 32px; max-width: 560px; margin-left: auto; margin-right: auto; }
/* TESTIMONIALS */
.testimonials-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 24px; }
.testimonial { background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; }
.testimonial-stars { color: var(--orange); font-size: 18px; margin-bottom: 16px; }
.testimonial-text { font-size: 15px; color: var(--text-dim); line-height: 1.7; margin-bottom: 20px; font-style: italic; }
.testimonial-author { display: flex; align-items: center; gap: 12px; }
.testimonial-avatar { width: 40px; height: 40px; border-radius: 50%; background: var(--orange); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 16px; color: #fff; flex-shrink: 0; }
.testimonial-name { font-weight: 700; font-size: 14px; }
.testimonial-role { font-size: 12px; color: var(--text-dim); }
/* PRICING */
.pricing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 24px; align-items: start; }
.pricing-card { background: var(--dark2); border: 1px solid var(--border); border-radius: var(--radius); padding: 32px; position: relative; }
.pricing-card.featured { border-color: var(--orange); background: rgba(255,136,34,0.04); }
.pricing-badge { display: inline-block; background: var(--orange); color: #fff; font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 4px; margin-bottom: 16px; letter-spacing: 0.5px; text-transform: uppercase; }
.pricing-name { font-size: 20px; font-weight: 700; margin-bottom: 8px; }
.pricing-price { font-size: 42px; font-weight: 800; margin-bottom: 4px; }
.pricing-price span { font-size: 16px; font-weight: 400; color: var(--text-dim); }
.pricing-desc { font-size: 14px; color: var(--text-dim); margin-bottom: 24px; }
.pricing-features { list-style: none; margin-bottom: 28px; display: flex; flex-direction: column; gap: 10px; }
.pricing-features li { font-size: 14px; display: flex; align-items: center; gap: 8px; }
.pricing-features li::before { content: "✓"; color: var(--orange); font-weight: 700; flex-shrink: 0; }
.pricing-features li.dim { color: var(--text-dim); }
.pricing-features li.dim::before { content: "–"; color: var(--border); }
.btn-plan { display: block; text-align: center; padding: 14px 24px; border-radius: 8px; font-size: 15px; font-weight: 700; transition: all 0.2s; }
.btn-plan.primary { background: var(--orange); color: #fff; }
.btn-plan.primary:hover { background: var(--orange2); text-decoration: none; }
.btn-plan.outline { border: 2px solid var(--border); color: var(--text); }
.btn-plan.outline:hover { border-color: var(--orange); color: var(--orange); text-decoration: none; }
.pricing-guarantee { text-align: center; margin-top: 32px; font-size: 13px; color: var(--text-dim); }
/* FAQ */
.faq { max-width: 760px; margin: 0 auto; }
.faq-item { border-bottom: 1px solid var(--border); padding: 24px 0; }
.faq-q { font-size: 17px; font-weight: 700; margin-bottom: 12px; }
.faq-a { font-size: 15px; color: var(--text-dim); line-height: 1.7; }
/* BOTTOM CTA */
.bottom-cta { text-align: center; padding: 80px 20px; background: linear-gradient(180deg, transparent, rgba(255,136,34,0.05)); }
.bottom-cta h2 { font-size: clamp(28px, 4vw, 44px); font-weight: 800; margin-bottom: 16px; }
.bottom-cta p { font-size: 18px; color: var(--text-dim); margin-bottom: 40px; max-width: 560px; margin-left: auto; margin-right: auto; }
/* FOOTER */
footer { text-align: center; padding: 40px 20px; border-top: 1px solid var(--border); color: var(--text-dim); font-size: 14px; }
.footer-logo { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 12px; }
.footer-logo span { color: var(--orange); }
@media (max-width: 600px) {
nav { padding: 14px 20px; }
.nav-links { display: none; }
.demo-stats { grid-template-columns: repeat(2, 1fr); }
.hero-stats { gap: 24px; }
}
.pricing-annual { font-size: 13px; color: var(--text-dim); margin-top: -2px; margin-bottom: 20px; }
.pricing-annual strong { color: var(--orange); }
.scarcity-box { background: rgba(255,60,0,0.1); border: 1px solid rgba(255,60,0,0.35); border-radius: 8px; padding: 12px 16px; margin-bottom: 18px; font-size: 13px; line-height: 1.5; }
.scarcity-box strong { color: #ff4422; display: block; font-size: 14px; margin-bottom: 4px; }
</style>
</head>
<body>
<!-- NAV -->
<nav>
<div class="nav-logo">Batch<span>Tube</span></div>
<div class="nav-links">
<a href="#features">Features</a>
<a href="#how-it-works">How It Works</a>
<a href="#pricing">Pricing</a>
<a href="#walkthrough">Demo</a>
<a href="#faq">FAQ</a>
<a href="/affiliates.html">Affiliates</a>
</div>
<a href="#pricing" class="nav-cta">Get BatchTube Free</a>
</nav>
<!-- HERO -->
<section class="hero">
<div class="hero-badge">DESKTOP APP &bull; WINDOWS &bull; MAC &bull; LINUX</div>
<h1>Stop Downloading YouTube Videos<br><span>One at a Time.</span></h1>
<p>BatchTube processes entire playlists, channels, and bulk URL lists — with transcripts, MP3 extraction, and AI summaries built in. Runs locally. No cloud. No data leaks.</p>
<div class="hero-btns">
<a href="#pricing" class="btn-primary">Download BatchTube Free &rarr;</a>
<a href="#features" class="btn-secondary">See Features</a>
</div>
<p class="hero-sub">Free forever &bull; No account required &bull; Start in 60 seconds</p>
<div class="hero-stats">
<div class="hero-stat"><div class="hero-stat-num">500+</div><div class="hero-stat-label">Videos per batch</div></div>
<div class="hero-stat"><div class="hero-stat-num">6</div><div class="hero-stat-label">Output formats</div></div>
<div class="hero-stat"><div class="hero-stat-num">3</div><div class="hero-stat-label">Platforms supported</div></div>
<div class="hero-stat"><div class="hero-stat-num">0</div><div class="hero-stat-label">Cloud dependencies</div></div>
</div>
</section>
<!-- DEMO WINDOW -->
<div class="demo">
<div class="demo-window">
<div class="demo-bar">
<div class="demo-dot red"></div>
<div class="demo-dot yellow"></div>
<div class="demo-dot green"></div>
<div class="demo-title">BatchTube — localhost:8000</div>
</div>
<div class="demo-body" style="padding: 0; overflow: hidden;">
<img src="/batchtube-demo.gif" alt="BatchTube app walkthrough — batch download, queue management, settings" style="width:100%; display:block; border-radius: 0 0 12px 12px;" loading="lazy" />
</div>
<!-- FEATURES -->
<section class="section" id="features">
<div class="section-label">Features</div>
<h2 class="section-title">Everything your YouTube workflow needs.</h2>
<p class="section-sub">Six tools in one. All running locally on your machine.</p>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">&#9889;</div>
<div class="feature-title">Batch Processing</div>
<div class="feature-desc">Paste a playlist URL, a channel URL, or a CSV of hundreds of links. BatchTube queues and processes everything in one run — no babysitting required.</div>
</div>
<div class="feature-card">
<div class="feature-icon">&#128221;</div>
<div class="feature-title">Transcript Extraction</div>
<div class="feature-desc">Powered by Whisper — OpenAI's speech recognition model running locally. Timestamped, accurate, exportable. Every word from every video, ready to repurpose.</div>
</div>
<div class="feature-card">
<div class="feature-icon">&#129504;</div>
<div class="feature-title">AI Summaries</div>
<div class="feature-desc">Get the key points from any video without watching a second of footage. AI summaries extract topics, takeaways, and action items automatically.</div>
</div>
<div class="feature-card">
<div class="feature-icon">&#128202;</div>
<div class="feature-title">Metadata Export</div>
<div class="feature-desc">Export structured JSON and CSV — titles, descriptions, view counts, upload dates, channel data. Plug directly into your research or analytics workflow.</div>
</div>
<div class="feature-card">
<div class="feature-icon">&#128247;</div>
<div class="feature-title">Real-Time Progress</div>
<div class="feature-desc">Live WebSocket dashboard shows every download as it happens. Queue status, completion rates, error logs — full visibility into your batch at all times.</div>
</div>
<div class="feature-card">
<div class="feature-icon">&#128279;</div>
<div class="feature-title">MCP Integration</div>
<div class="feature-desc">BatchTube ships with a built-in MCP server. Connect it directly to Claude, Cursor, or any AI assistant that supports the Model Context Protocol.</div>
</div>
</div>
</section>
<!-- HOW IT WORKS -->
<section class="section" id="how-it-works">
<div class="section-label">How It Works</div>
<h2 class="section-title">Running in 60 seconds.</h2>
<p class="section-sub">No cloud account. No API keys. No configuration headaches.</p>
<div class="steps">
<div class="step">
<div class="step-num">1</div>
<div class="step-title">Download &amp; Run</div>
<div class="step-desc">Download BatchTube and double-click start.bat (Windows) or run the shell script. Your browser opens automatically.</div>
</div>
<div class="step">
<div class="step-num">2</div>
<div class="step-title">Paste Your URLs</div>
<div class="step-desc">Paste a YouTube playlist, channel URL, or upload a CSV of hundreds of video links. BatchTube handles the rest.</div>
</div>
<div class="step">
<div class="step-num">3</div>
<div class="step-title">Choose Your Output</div>
<div class="step-desc">Select video quality, enable transcript extraction, AI summaries, MP3 audio, or metadata export. Mix and match.</div>
</div>
<div class="step">
<div class="step-num">4</div>
<div class="step-title">Watch It Run</div>
<div class="step-desc">The live dashboard tracks every download in real time. Walk away. Come back to a completed batch — files on your hard drive, yours to keep.</div>
</div>
</div>
</section>
<!-- WALKTHROUGH -->
<section class="section" id="walkthrough">
<div class="section-label">See It In Action</div>
<h2 class="section-title">The full workflow. 60 seconds.</h2>
<p class="section-sub">Real app. Real interface. No demo smoke and mirrors.</p>
<!-- Main animated walkthrough -->
<div style="max-width:960px;margin:0 auto 48px;border-radius:12px;overflow:hidden;border:1px solid var(--border);box-shadow:0 20px 60px rgba(0,0,0,0.6);">
<div style="background:var(--dark3);padding:12px 16px;display:flex;align-items:center;gap:8px;border-bottom:1px solid var(--border);">
<div style="width:12px;height:12px;border-radius:50%;background:#ff5f57;"></div>
<div style="width:12px;height:12px;border-radius:50%;background:#febc2e;"></div>
<div style="width:12px;height:12px;border-radius:50%;background:#28c840;"></div>
<div style="flex:1;text-align:center;font-size:13px;color:var(--text-dim);">BatchTube — localhost:8000</div>
</div>
<img src="/batchtube-walkthrough.gif" alt="BatchTube full feature walkthrough" style="width:100%;display:block;" loading="lazy" />
</div>
<!-- Feature GIF grid -->
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:24px;">
<div style="background:var(--dark2);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;">
<img src="/feature-new-job.gif" alt="Create a new extraction job" style="width:100%;display:block;" loading="lazy" />
<div style="padding:16px;">
<div style="font-size:15px;font-weight:700;margin-bottom:6px;">&#9889; New Extraction Job</div>
<div style="font-size:13px;color:var(--text-dim);">Single URL, playlist, channel handle, or CSV list. Configure what to extract in seconds.</div>
</div>
</div>
<div style="background:var(--dark2);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;">
<img src="/feature-jobs.gif" alt="Track batch processing progress" style="width:100%;display:block;" loading="lazy" />
<div style="padding:16px;">
<div style="font-size:15px;font-weight:700;margin-bottom:6px;">&#128202; Live Progress Tracking</div>
<div style="font-size:13px;color:var(--text-dim);">Real-time job dashboard. See every batch as it processes — status, progress, completion history.</div>
</div>
</div>
<div style="background:var(--dark2);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;">
<img src="/feature-settings.gif" alt="MCP server integration and settings" style="width:100%;display:block;" loading="lazy" />
<div style="padding:16px;">
<div style="font-size:15px;font-weight:700;margin-bottom:6px;">&#128279; MCP Server Built In</div>
<div style="font-size:13px;color:var(--text-dim);">Connect BatchTube directly to Claude, Cursor, or any AI assistant. One config line. Done.</div>
</div>
</div>
</div>
</section>
<!-- MID-PAGE CTA -->
<div class="section">
<div class="mid-cta">
<h2>Stop doing this manually.</h2>
<p>Every hour you spend downloading videos one at a time is an hour you are not creating, researching, or building. BatchTube gives that time back.</p>
<a href="#pricing" class="btn-primary">Get BatchTube Free &rarr;</a>
</div>
</div>
<!-- TESTIMONIALS -->
<section class="section" id="testimonials">
<div class="section-label">What People Are Saying</div>
<h2 class="section-title">Built for people who work at scale.</h2>
<p class="section-sub">Content creators, researchers, educators — anyone who works with YouTube seriously.</p>
<div class="testimonials-grid">
<div class="testimonial">
<div class="testimonial-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
<p class="testimonial-text">&ldquo;I research competitor channels for clients every week. BatchTube cut my research time from 6 hours to 45 minutes. I paste the channel URL, walk away, and come back to a full transcript library. Nothing else does this.&rdquo;</p>
<div class="testimonial-author">
<div class="testimonial-avatar">M</div>
<div><div class="testimonial-name">Marcus T.</div><div class="testimonial-role">YouTube Strategy Consultant</div></div>
</div>
</div>
<div class="testimonial">
<div class="testimonial-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
<p class="testimonial-text">&ldquo;I teach a media studies course and needed to archive 200+ videos for my curriculum before they disappeared. BatchTube downloaded everything overnight — transcripts included. My students now have a searchable library. Incredible tool.&rdquo;</p>
<div class="testimonial-author">
<div class="testimonial-avatar">D</div>
<div><div class="testimonial-name">Dr. Diane K.</div><div class="testimonial-role">University Media Studies Professor</div></div>
</div>
</div>
<div class="testimonial">
<div class="testimonial-stars">&#9733;&#9733;&#9733;&#9733;&#9733;</div>
<p class="testimonial-text">&ldquo;The MCP integration is what sold me. I connected BatchTube directly to Claude and now I can ask questions about any YouTube channel's content without watching a single video. This is the future of research.&rdquo;</p>
<div class="testimonial-author">
<div class="testimonial-avatar">R</div>
<div><div class="testimonial-name">Ryan S.</div><div class="testimonial-role">AI-Assisted Content Creator</div></div>
</div>
</div>
</div>
</section>
<!-- PRICING -->
<section class="section" id="pricing">
<div class="section-label">Pricing</div>
<h2 class="section-title">Start free. Scale when you're ready.</h2>
<p class="section-sub">Every plan runs locally on your machine. Your data never leaves your hard drive.</p>
<div class="pricing-grid">
<div class="pricing-card">
<div class="pricing-name">Free</div>
<div class="pricing-price">$0</div>
<div class="pricing-desc">Try it. No account required.</div>
<ul class="pricing-features">
<li>3 videos per batch</li>
<li>720p max resolution</li>
<li>MP3 extraction</li>
<li class="dim">Transcripts</li>
<li class="dim">Batch CSV upload</li>
<li class="dim">AI summaries</li>
<li class="dim">Priority support</li>
</ul>
<a href="#download" class="btn-plan outline">Download Free — Start Today</a>
</div>
<div class="pricing-card featured">
<div class="pricing-badge">Most Popular</div>
<div class="pricing-name">Creator</div>
<div class="pricing-price">$19<span>/mo</span></div>
<div class="pricing-annual">Or <strong>$190/yr</strong> &mdash; save 2 months</div>
<div class="pricing-desc">For serious content creators.</div>
<ul class="pricing-features">
<li>100 downloads per day</li>
<li>1080p max resolution</li>
<li>MP3 extraction</li>
<li>Transcripts</li>
<li>Batch CSV upload</li>
<li>AI summaries</li>
<li class="dim">Priority support</li>
</ul>
<a href="https://qmg.thrivecart.com/batchtube-creator/" class="btn-plan primary">Start Creator &mdash; $19/mo &rarr;</a>
</div>
<div class="pricing-card">
<div class="pricing-name">Pro</div>
<div class="pricing-price">$39<span>/mo</span></div>
<div class="pricing-annual">Or <strong>$790/yr</strong> &mdash; save with annual</div>
<div class="pricing-desc">Unlimited power. Zero limits.</div>
<ul class="pricing-features">
<li>Unlimited downloads</li>
<li>4K max resolution</li>
<li>MP3 extraction</li>
<li>Transcripts</li>
<li>Batch CSV upload</li>
<li>AI summaries</li>
<li>Priority support</li>
</ul>
<a href="https://qmg.thrivecart.com/batchtube-pro/" class="btn-plan outline">Go Pro &mdash; $39/mo &rarr;</a>
</div>
<div class="pricing-card" style="border-color: #9933ff; background: rgba(153,51,255,0.04);">
<div class="pricing-badge" style="background:#9933ff;">&#127775; Studio</div>
<div class="pricing-name">Studio</div>
<div class="pricing-price">$79<span>/mo</span></div>
<div class="pricing-annual">Or <strong>$790/yr</strong> &mdash; save 2 months</div>
<div class="pricing-desc">For agencies &amp; power teams.</div>
<ul class="pricing-features">
<li>Unlimited downloads</li>
<li>4K max resolution</li>
<li>MP3 extraction</li>
<li>Transcripts</li>
<li>Batch CSV upload</li>
<li>AI summaries</li>
<li>3 team seats</li>
<li>API access</li>
<li>Priority support</li>
</ul>
<a href="https://qmg.thrivecart.com/batchtube-studio/" class="btn-plan primary" style="background:#9933ff;">Get Studio &mdash; $79/mo &rarr;</a>
</div>
<div class="pricing-card" style="border-color: #ffcc00; background: rgba(255,204,0,0.03);">
<div class="pricing-badge" style="background:#ffcc00; color:#000;">&#128293; Best Value</div>
<div class="pricing-name">Lifetime</div>
<div class="pricing-price">$197<span> once</span></div>
<div class="pricing-desc">Pay once. Own it forever.</div>
<div class="scarcity-box"><strong>&#128293; FOUNDING MEMBER PRICE &mdash; First 100 licenses only</strong>After 100 licenses: price goes to $247. Forever.</div>
<ul class="pricing-features">
<li>Unlimited downloads</li>
<li>4K max resolution</li>
<li>MP3 extraction</li>
<li>Transcripts</li>
<li>Batch CSV upload</li>
<li>AI summaries</li>
<li>Lifetime updates</li>
</ul>
<a href="https://qmg.thrivecart.com/batchtube-lifetime/" class="btn-plan primary" style="background:#ffcc00; color:#000;">&#9889; Lock in $197 before it's gone &rarr;</a>
</div>
</div>
<p class="pricing-guarantee">&#128737; 30-Day Money-Back Guarantee on all paid plans &bull; No questions asked</p>
</section>
<!-- FAQ -->
<section class="section" id="faq">
<div class="section-label">FAQ</div>
<h2 class="section-title">Questions answered.</h2>
<div class="faq">
<div class="faq-item">
<div class="faq-q">Is downloading YouTube videos legal?</div>
<div class="faq-a">Downloading YouTube videos for personal use, research, education, and archival purposes is widely practiced and legally protected in many jurisdictions under fair use doctrine. BatchTube is used by researchers, educators, journalists, and content archivists worldwide. We do not scrape YouTube's platform or violate rate limits. Use BatchTube responsibly, within the bounds of your intended purpose.</div>
</div>
<div class="faq-item">
<div class="faq-q">Does BatchTube work on Mac and Linux?</div>
<div class="faq-a">Yes. BatchTube runs on Windows, macOS, and Linux. The application runs a local server that opens in your browser — the same interface works identically across all three platforms. Windows users get a one-click start.bat launcher. Mac and Linux users run a shell script.</div>
</div>
<div class="faq-item">
<div class="faq-q">Does BatchTube violate YouTube's Terms of Service?</div>
<div class="faq-a">BatchTube is powered by a robust open-source engine maintained by a global developer community. YouTube&#8217;s ToS restricts commercial redistribution of downloaded content &#8212; not personal use or research. BatchTube does not redistribute content. It downloads to your local machine for your own use. Consult your own legal counsel if you have specific compliance questions.</div>
</div>
<div class="faq-item">
<div class="faq-q">Does BatchTube require an internet connection?</div>
<div class="faq-a">BatchTube needs an internet connection to download content from YouTube — that is the nature of the task. But the application itself runs entirely locally on your machine. Your downloaded files, transcripts, and AI summaries are stored on your hard drive. No cloud account required. No data sent to our servers. Your content stays yours.</div>
</div>
<div class="faq-item">
<div class="faq-q">How accurate are the transcripts and AI summaries?</div>
<div class="faq-a">Transcripts are generated by Whisper — OpenAI's speech recognition model — running locally on your machine. Accuracy is typically 95%+ for clear English audio. AI summaries extract key points, topics, and takeaways from the transcript automatically. Both outputs are editable and exportable.</div>
</div>
<div class="faq-item">
<div class="faq-q">What happens if YouTube changes something and BatchTube breaks?</div>
<div class="faq-a">BatchTube&#8217;s download engine is powered by a robust open-source engine maintained by a global developer community that pushes updates within hours of any YouTube change. Creator and Pro subscribers receive automatic updates. Lifetime customers receive every update forever. Your workflow stays uninterrupted.</div>
</div>
</div>
</section>
<!-- BOTTOM CTA -->
<div class="bottom-cta">
<h2>Your competitors are already automating their research.</h2>
<p>Are you still downloading one video at a time?</p>
<a href="#pricing" class="btn-primary" style="font-size:18px; padding:18px 44px;">Download BatchTube Now &mdash; Free to Start &rarr;</a>
<p style="margin-top:16px; font-size:13px; color:var(--text-dim);">No account required &bull; Windows, Mac &amp; Linux &bull; 30-day guarantee on paid plans</p>
</div>
<!-- FOOTER -->
<footer>
<div class="footer-logo">Batch<span>Tube</span></div>
<p style="margin-bottom:12px;">Built by <a href="https://intentures.org">Intentures LLC</a> &bull; <a href="https://mautic.intentures.org/form/2" target="_blank" rel="noopener">Contact Us</a></p>
<p>&copy; 2026 Intentures LLC. All rights reserved.</p>
</footer>
</body>
</html>