Skip to content
This repository was archived by the owner on Aug 26, 2026. It is now read-only.

Commit 16d3772

Browse files
raccommodeclaude
andcommitted
feat: add discover, following, recordings, settings, watch pages + CI release
- Add Discover page with gender/tag/search filters - Add Following page with Chaturbate account sync - Add Recordings page with built-in video player - Add Settings page for account, FlareSolverr, tag blacklist - Add Watch page for live stream viewing - Add Chaturbate authentication (login/session/cookies) - Add FlareSolverr integration for Cloudflare bypass - Update CI workflow to build Docker + create GitHub Release from version.json changelog - Rewrite README in English with screenshots Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2d5849f commit 16d3772

35 files changed

Lines changed: 5899 additions & 197 deletions

.env.example

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,14 @@ CB_RESOLVER_ENABLED=true
99
# CB_COOKIE="session=...; other=..."
1010
# Optionnel: mot de passe pour protéger l'accès
1111
# PASSWORD=your_secure_password
12+
13+
# Chaturbate Authentication (optional - enables Following page and better stream quality)
14+
# CHATURBATE_USERNAME=your_chaturbate_username
15+
# CHATURBATE_PASSWORD=your_chaturbate_password
16+
17+
# FlareSolverr (optional - Cloudflare bypass, auto-configured with docker-compose)
18+
# FLARESOLVERR_URL=http://flaresolverr:8191
19+
# FLARESOLVERR_MAX_TIMEOUT=60000
20+
21+
# Chaturbate request delay in seconds (rate limiting)
22+
# CB_REQUEST_DELAY=1.0
Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,31 @@
1-
name: Build and Push Docker Image
1+
name: Build, Push & Release
22

33
on:
44
push:
55
tags:
66
- '*'
7-
release:
8-
types: [published]
97

108
jobs:
119
build-and-push:
1210
runs-on: ubuntu-latest
1311
permissions:
14-
contents: read
12+
contents: write
1513
packages: write
16-
14+
1715
steps:
1816
- name: Checkout
1917
uses: actions/checkout@v4
20-
18+
2119
- name: Set up Docker Buildx
2220
uses: docker/setup-buildx-action@v3
23-
21+
2422
- name: Log in to GitHub Container Registry
2523
uses: docker/login-action@v3
2624
with:
2725
registry: ghcr.io
2826
username: ${{ github.actor }}
2927
password: ${{ secrets.GITHUB_TOKEN }}
30-
28+
3129
- name: Extract metadata
3230
id: meta
3331
uses: docker/metadata-action@v5
@@ -36,7 +34,7 @@ jobs:
3634
tags: |
3735
type=ref,event=tag
3836
type=raw,value=latest
39-
37+
4038
- name: Build and push
4139
uses: docker/build-push-action@v5
4240
with:
@@ -46,3 +44,27 @@ jobs:
4644
labels: ${{ steps.meta.outputs.labels }}
4745
cache-from: type=gha
4846
cache-to: type=gha,mode=max
47+
48+
- name: Generate release notes from version.json
49+
id: notes
50+
run: |
51+
VERSION=$(jq -r '.version' version.json)
52+
BODY=$(jq -r '.changelog | map("- " + .) | join("\n")' version.json)
53+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
54+
{
55+
echo "body<<EOF"
56+
echo "## Changelog"
57+
echo ""
58+
echo "$BODY"
59+
echo ""
60+
echo "---"
61+
echo "Docker image: \`ghcr.io/raccommode/p-streamrec:${GITHUB_REF_NAME}\`"
62+
echo "EOF"
63+
} >> "$GITHUB_OUTPUT"
64+
65+
- name: Create GitHub Release
66+
uses: softprops/action-gh-release@v2
67+
with:
68+
name: ${{ steps.notes.outputs.version }}
69+
body: ${{ steps.notes.outputs.body }}
70+
generate_release_notes: false

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ __pycache__/
99
.vscode/
1010
.idea/
1111
.windsurf
12-
.gitignore
12+
.claude/

README.md

Lines changed: 81 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -4,132 +4,119 @@
44
[![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://www.docker.com/)
55
[![Open Source](https://img.shields.io/badge/Open%20Source-Yes-green.svg)](https://github.com/raccommode/P-StreamRec)
66

7-
**Automatic recording of Chaturbate and m3u8 streams with a modern web interface**
7+
**Automatic Chaturbate & m3u8 stream recorder with a modern web interface.**
88

9-
![P-StreamRec Interface](screen.png)
9+
## Features
1010

11-
## ✨ Features
11+
- **24/7 automatic recording** — monitors models and records when they go live
12+
- **Auto MP4 conversion** — converts TS to compressed MP4 in background (50-70% smaller)
13+
- **Discover** — browse live Chaturbate models with gender, tag, and search filters
14+
- **Following** — sync and view your followed models from your Chaturbate account
15+
- **Recordings** — manage all recordings with built-in video player
16+
- **Live Watch** — watch streams directly in the browser with HLS player
17+
- **Chaturbate auth** — login for better stream quality and followed models sync
18+
- **FlareSolverr** — automatic Cloudflare bypass via dedicated container
19+
- **Settings** — manage account, FlareSolverr status, tag blacklist
20+
- **Password protection** — optional login to secure the interface
21+
- **GitOps updates** — update the app directly from the UI
22+
- **Docker ready** — one command to get started
1223

13-
- 🎥 **24/7 automatic recording** - Monitors and records when users go live
14-
- 🎬 **Auto MP4 conversion** - Automatically converts recordings to compressed MP4 after stream ends
15-
- 🌐 **Web interface** - Manage recordings and watch replays in browser
16-
- 📦 **Docker ready** - One command to get started
17-
- 🔄 **GitOps updates** - Update directly from the interface
18-
- 🎯 **Chaturbate + m3u8 support** - Works with any HLS stream
19-
- 💾 **Smart storage** - Unique ID per recording, automatic compression
20-
- 📊 **Size display** - Shows file sizes in MB or GB (>1000 MB)
24+
## Screenshots
2125

22-
## ⚙️ Configuration (Environment Variables)
26+
| Discover | Following | Recordings |
27+
|----------|-----------|------------|
28+
| ![Discover](discover.png) | ![Following](following.png) | ![Recordings](recordings.png) |
2329

24-
| Variable | Default | Description |
25-
|----------|---------|-------------|
26-
| `OUTPUT_DIR` | `/data` | Recordings folder (Docker volume) |
27-
| `PORT` | `8080` | Web interface port |
28-
| `FFMPEG_PATH` | `ffmpeg` | Path to ffmpeg |
29-
| `HLS_TIME` | `4` | HLS segment duration (seconds) |
30-
| `HLS_LIST_SIZE` | `6` | Number of segments in playlist |
31-
| `CB_RESOLVER_ENABLED` | `true` | **Enable Chaturbate support** |
32-
| `CB_COOKIE` | - | Chaturbate session cookie (optional) |
33-
| `PASSWORD` | - | **Password to protect access** (optional) |
34-
| `AUTO_RECORD_USERS` | - | Comma-separated list of users to auto-record |
35-
| `TZ` | `UTC` | Timezone (e.g., `America/New_York`) |
36-
37-
## 🚀 Quick Start
38-
39-
### Docker Run
40-
```bash
41-
docker run -d \
42-
--name p-streamrec \
43-
-p 8080:8080 \
44-
-v ./data:/data \
45-
-e CB_RESOLVER_ENABLED=true \
46-
ghcr.io/raccommode/p-streamrec:latest
47-
```
30+
## Quick Start
31+
32+
### Docker Compose (recommended, includes FlareSolverr)
4833

49-
### Docker Compose
5034
```yaml
5135
version: "3.8"
5236
services:
37+
flaresolverr:
38+
image: ghcr.io/flaresolverr/flaresolverr:latest
39+
environment:
40+
- LOG_LEVEL=info
41+
ports:
42+
- "8191:8191"
43+
restart: unless-stopped
44+
5345
p-streamrec:
5446
image: ghcr.io/raccommode/p-streamrec:latest
47+
depends_on:
48+
- flaresolverr
49+
environment:
50+
- CB_RESOLVER_ENABLED=true
51+
- FLARESOLVERR_URL=http://flaresolverr:8191
5552
ports:
5653
- "8080:8080"
5754
volumes:
5855
- ./data:/data
59-
environment:
60-
- CB_RESOLVER_ENABLED=true
6156
restart: unless-stopped
6257
```
6358
64-
**Access:** `http://localhost:8080`
65-
66-
## 🔐 Password Protection (Optional)
67-
68-
Pour protéger l'accès à l'interface avec un mot de passe, définissez la variable `PASSWORD`:
59+
### Docker Run (simple)
6960
70-
```yaml
71-
environment:
72-
- PASSWORD=votre_mot_de_passe_securise
61+
```bash
62+
docker run -d --name p-streamrec \
63+
-p 8080:8080 -v ./data:/data \
64+
-e CB_RESOLVER_ENABLED=true \
65+
ghcr.io/raccommode/p-streamrec:latest
7366
```
7467

75-
**Comportement:**
76-
- **Sans PASSWORD**: Accès direct à l'interface (comportement par défaut)
77-
- **Avec PASSWORD**: Redirection vers `/login` pour authentification
78-
- Les sessions sont conservées pendant 30 jours
79-
- Bouton de déconnexion 🚪 disponible dans l'interface
80-
81-
## 📖 Usage
68+
**Access:** `http://localhost:8080`
8269

83-
1. **Add a model**: Click **+** → Enter Chaturbate username or m3u8 URL
84-
2. **Auto-record**: System checks every 2 minutes and records when live
85-
3. **Auto-convert**: When stream ends, system converts TS to MP4 (50-70% smaller)
86-
4. **Watch replays**: Click model card → **Replays** tab (TS or MP4 available)
87-
5. **Update**: Click **GitOps** button in header to update app (Git deployment only)
70+
## Configuration
8871

89-
**Recording Format:**
90-
- Original: `/data/records/<username>/YYYYMMDD_HHMMSS_ID.ts` (MPEG-TS)
72+
| Variable | Default | Description |
73+
|----------|---------|-------------|
74+
| `OUTPUT_DIR` | `/data` | Recordings folder |
75+
| `PORT` | `8080` | Web interface port |
76+
| `FFMPEG_PATH` | `ffmpeg` | Path to FFmpeg |
77+
| `CB_RESOLVER_ENABLED` | `true` | Enable Chaturbate support |
78+
| `CB_REQUEST_DELAY` | `1.0` | Delay between Chaturbate requests (seconds) |
79+
| `PASSWORD` || Password to protect the interface (optional) |
80+
| `AUTO_RECORD_USERS` || Comma-separated usernames to auto-record |
81+
| `CHATURBATE_USERNAME` || Chaturbate login (optional, enables Following + better quality) |
82+
| `CHATURBATE_PASSWORD` || Chaturbate password (optional) |
83+
| `FLARESOLVERR_URL` || FlareSolverr URL (e.g. `http://flaresolverr:8191`) |
84+
| `TZ` | `UTC` | Timezone (e.g. `America/Toronto`) |
85+
86+
## Usage
87+
88+
1. **Add a model** — click **+**, enter a Chaturbate username or m3u8 URL
89+
2. **Auto-record** — the system checks every 2 minutes and records when live
90+
3. **Auto-convert** — when the stream ends, TS is converted to MP4 automatically
91+
4. **Watch live** — click a model card to open the live player
92+
5. **Browse replays** — go to the Recordings page to watch or delete recordings
93+
94+
### Recording format
95+
96+
- Original: `/data/records/<username>/YYYYMMDD_HHMMSS_ID.ts` (MPEG-TS, lossless)
9197
- Converted: `/data/records/<username>/YYYYMMDD_HHMMSS_ID.mp4` (H.264, auto-generated)
92-
- Each recording has unique ID: `username_YYYYMMDD_HHMMSS_sessionID`
9398

94-
## 💻 Development
99+
### Storage estimates
100+
101+
| Format | Size per hour |
102+
|--------|---------------|
103+
| TS (original) | ~2–4 GB |
104+
| MP4 (converted) | ~600 MB–1.2 GB |
105+
106+
## Development
95107

96108
```bash
109+
git clone https://github.com/raccommode/P-StreamRec.git
110+
cd P-StreamRec
97111
python -m venv .venv && source .venv/bin/activate
98112
pip install -r requirements.txt
99113
uvicorn app.main:app --reload
100114
```
101115

102-
## 📂 File Management
103-
104-
**Automatic Conversion:**
105-
- System automatically converts TS → MP4 when stream ends
106-
- MP4 files are 50-70% smaller (H.264 codec, CRF 23)
107-
- Conversion runs in background, no user action needed
108-
- Both TS and MP4 available in Replays tab
109-
110-
**Play recordings:**
111-
- **Browser**: Use Replays tab (supports TS and MP4)
112-
- **VLC/MPV**: Open files directly from `/data/records/<username>/`
113-
- **MP4**: Better for streaming, smaller file size
114-
- **TS**: Original quality, no re-encoding
115-
116-
**Manual conversion (if needed):**
117-
```bash
118-
ffmpeg -i input.ts -c:v libx264 -crf 23 -c:a aac output.mp4
119-
```
120-
121-
## ⚠️ Notes
122-
123-
- **Storage**: TS ~2-4 GB/hour, MP4 ~600 MB-1.2 GB/hour (after conversion)
124-
- **Sizes displayed**: MB for files < 1000 MB, GB for larger files
125-
- **Unique IDs**: Each recording has timestamp + session ID for easy identification
126-
- Use only for public, legally accessible content
116+
**Stack:** FastAPI, SQLite (aiosqlite), HLS.js, FFmpeg, Docker
127117

128-
## 📜 License
118+
## License
129119

130-
**Non-Commercial Open Source License** - See [LICENSE](LICENSE)
120+
**Non-Commercial Open Source License** See [LICENSE](LICENSE)
131121

132-
✅ Free to use, modify, and distribute
133-
❌ **No commercial use or revenue generation**
134-
🔄 Share modifications under same license
135-
📝 Attribution required
122+
Free to use, modify, and distribute — **no commercial use** — share modifications under same license — attribution required

app/api/auth.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
"""
2+
API Router: Chaturbate Authentication
3+
"""
4+
5+
from fastapi import APIRouter, HTTPException
6+
from pydantic import BaseModel
7+
from typing import Optional
8+
9+
router = APIRouter(prefix="/api/chaturbate", tags=["chaturbate-auth"])
10+
11+
# These will be set by main.py at startup
12+
_auth_service = None
13+
_flaresolverr = None
14+
15+
16+
def init(auth_service, flaresolverr=None):
17+
global _auth_service, _flaresolverr
18+
_auth_service = auth_service
19+
_flaresolverr = flaresolverr
20+
21+
22+
class LoginRequest(BaseModel):
23+
username: str
24+
password: str
25+
26+
27+
@router.post("/login")
28+
async def chaturbate_login(req: LoginRequest):
29+
"""Login to Chaturbate"""
30+
if not _auth_service:
31+
raise HTTPException(status_code=503, detail="Auth service not initialized")
32+
33+
result = await _auth_service.login(req.username, req.password)
34+
if not result.get("success"):
35+
raise HTTPException(status_code=401, detail=result.get("error", "Login failed"))
36+
37+
return result
38+
39+
40+
@router.get("/status")
41+
async def chaturbate_status():
42+
"""Get Chaturbate auth status"""
43+
status = {}
44+
if _auth_service:
45+
status = _auth_service.get_status()
46+
47+
flaresolverr_available = False
48+
if _flaresolverr:
49+
flaresolverr_available = await _flaresolverr.is_available()
50+
51+
status["flaresolverrAvailable"] = flaresolverr_available
52+
return status
53+
54+
55+
@router.post("/logout")
56+
async def chaturbate_logout():
57+
"""Clear Chaturbate session"""
58+
if not _auth_service:
59+
raise HTTPException(status_code=503, detail="Auth service not initialized")
60+
61+
await _auth_service.logout()
62+
return {"success": True}
63+
64+
65+
@router.post("/refresh")
66+
async def chaturbate_refresh():
67+
"""Force re-login using saved credentials"""
68+
if not _auth_service:
69+
raise HTTPException(status_code=503, detail="Auth service not initialized")
70+
71+
# Get saved credentials from DB
72+
auth_state = await _auth_service.db.get_auth_state()
73+
if not auth_state or not auth_state.get("username"):
74+
raise HTTPException(status_code=400, detail="No saved credentials")
75+
76+
# We can't re-login without the password (only hash is stored)
77+
raise HTTPException(
78+
status_code=400,
79+
detail="Please login again with your credentials"
80+
)

0 commit comments

Comments
 (0)