Hypertube
A full-stack streaming web app: search legally distributable torrents, watch them as they download, with adaptive-bitrate playback, subtitles, comments, and an OAuth2-secured REST API.
Built for the 42 school Hypertube project.
Overview
| Layer | Description | Key Tools |
|---|---|---|
| Backend | REST API, auth, torrent engine, transcoding | Spring Boot 4, Java 21, PostgreSQL, jlibtorrent, ffmpeg |
| Frontend | SPA / SSR client | Next.js 16, React 19, Redux Toolkit, HLS.js, shadcn/Radix UI |
| Infra | Reverse proxy + orchestration | Docker Compose, Nginx |
Features
Authentication & Profile
- Register/login with email, username, first/last name, and a hashed password (no plaintext storage).
- OAuth2 login via 42, Google, and GitHub (3 strategies, only 2 required).
- JWT-based stateless sessions.
- Forgot/reset password flow via email (Spring Mail).
- Preferred language (
EN/FR/AR), defaulting to English. - Edit own email, avatar, and profile info; view other users' public profiles (email stays private).
Library
- Search queries two external sources in parallel: YTS and archive.org.
- Results enriched with ratings/metadata via the OMDb API.
- Thumbnails show title, year, rating, and cover; watched vs. unwatched state is visually distinguished.
- No-query view falls back to the most popular/top-rated titles.
- Infinite scroll (async pagination, no "load more" link) with sorting/filtering by name, genre, rating, and year.
Video Playback
- Selecting a video starts a real BitTorrent download server-side via jlibtorrent (no
webtorrent/peerflix-style libraries). - Downloaded bytes are piped live into ffmpeg, which transcodes into multi-bitrate HLS (240p up to 4K, picked based on source resolution) so playback can start before the download finishes.
- Player (HLS.js) supports adaptive quality switching and seeking into already-downloaded ranges.
- English subtitles, plus the viewer's preferred language when available, fetched via OpenSubtitles and served as WebVTT/HLS subtitle tracks.
- Finished downloads are cached on disk; a scheduled job purges videos unwatched for 30+ days.
- Per-video comments (post + list).
REST API
POST /oauth/token— client-credentials grant for third-party API access.GET /public/top10— public front-page listing of top movies.- Full CRUD on users, movies, and comments per the spec (ownership checks return
403on cross-user writes). - OpenAPI/Swagger docs exposed via springdoc.
Project Structure
hypertube/
├── backend/ # Spring Boot API
│ └── src/main/java/com/hypertube/
│ ├── controller/ # Auth, User, Movie, Library, Comment, Streaming, Subtitle, OAuthToken, Public, ApiClient
│ ├── service/ # Business logic
│ │ ├── BtTorrentService.java / TorrentDownloadService.java # jlibtorrent download engine
│ │ ├── TranscodingService.java # ffmpeg → multi-quality HLS
│ │ ├── StreamingService.java # serves master/quality playlists & segments
│ │ ├── ScheduledMovieCleanupService.java # purges stale downloads
│ │ └── external/ # YtsService, ArchiveService, OmdbEnrichService, SubtitleService
│ ├── security/ # JWT filter, OAuth2 success/failure handlers, provisioning
│ ├── entity/, repository/, dto/, config/
│ └── ...
│
├── frontend/ # Next.js app
│ └── src/
│ ├── app/(auth)/ # signin, signup, forgot/reset password
│ ├── app/(home)/ # library, movie/[id], profile/[id], profile/me, history, saved-movies
│ ├── components/ # VideoPlayer (HLS.js), navbar, profile, history, ui (shadcn)
│ ├── services/ # API clients (moviesApi, commentApi, appsApi)
│ └── lib/ # Redux store, auth slice, api client
│
└── infra/
├── docker-compose.yml # postgres + backend + frontend + nginx
└── nginx.conf # routes /, /api/, /uploads/, /videos/
Tech Stack
Backend: Spring Boot 4 (Java 21), Spring Security + OAuth2 Client, Spring Data JPA, PostgreSQL, JJWT, jlibtorrent, ffmpeg (via ProcessBuilder), Apache Tika, springdoc-openapi.
Frontend: Next.js 16 / React 19, Redux Toolkit, HLS.js, Zod, shadcn/ui + Radix, Tailwind CSS, react-intersection-observer (infinite scroll).
Infra: Docker multi-stage builds (Maven → Temurin JRE for backend, Node → standalone Next.js runtime for frontend), Nginx reverse proxy, Docker Compose.
Getting Started
git clone <repo-url>
cd hypertube
cp .env.example .env # fill in DB, JWT, mail, OAuth (42/Google/GitHub), OMDb & OpenSubtitles keys
make # docker compose up --build
# or
make run # up without rebuilding
make down # tear down
Once running:
| Service | URL |
|---|---|
| App (via Nginx) | http://localhost |
| API directly | http://localhost:8081 |
| Swagger UI | http://localhost:8081/swagger-ui/index.html |
Required environment variables (see .env.example)
DB_URL,DB_USERNAME,DB_PASSWORD— PostgreSQLJWT_SECRET,ACCESS_TOKEN_EXPIRATIONMAIL_HOST,MAIL_PORT,MAIL_USERNAME,MAIL_PASSWORD— password reset emailsGOOGLE_CLIENT_ID/SECRET,FT_CLIENT_ID/SECRET(42),GITHUB_CLIENT_ID/SECRETOPENSUBTITLES_API_KEY,OPENSUBTITLES_LANGUAGESOMDB_API_KEYFRONTEND_URL,STORAGE_DIR
All secrets stay in a local, git-ignored .env — never committed.
How Streaming Works
- User selects a result → backend resolves a torrent (YTS magnet or archive.org file) and starts the download with jlibtorrent.
- As pieces arrive, a feeder thread streams the partial file into ffmpeg's stdin.
- ffmpeg transcodes into several HLS quality renditions (240p–4K, capped to source resolution) and writes segments + playlists to disk as they're ready.
- The frontend's HLS.js player starts playback against
/stream/{movieId}/master.m3u8as soon as the first segments exist, switching quality adaptively. - On completion, the file is kept on disk for instant replay; a scheduled cleanup job deletes anything unwatched for 30+ days.
Security Notes
- Passwords are hashed, never stored in plain text.
- Stateless JWT auth (no server-side sessions) + Spring Security OAuth2 login flow.
- CORS is restricted to known frontend origins.
- Profile update endpoints enforce ownership (
403on attempts to edit another user). - Credentials and API keys are environment-driven via
.env, excluded from git.
Disclaimer
This project only integrates with sources that provide royalty-free or legally distributable content (e.g. YTS, archive.org). Built for educational purposes as part of the 42 school curriculum — do not use to download or stream copyrighted material without proper rights.
