625 lines
11 KiB
Markdown
625 lines
11 KiB
Markdown
|
|
# Build Guide - IPTV Streaming Application
|
||
|
|
|
||
|
|
## Quick Start
|
||
|
|
|
||
|
|
### Docker Build & Run
|
||
|
|
```bash
|
||
|
|
# Build the Docker image
|
||
|
|
docker-compose build
|
||
|
|
|
||
|
|
# Start the container
|
||
|
|
docker-compose up -d
|
||
|
|
|
||
|
|
# View logs
|
||
|
|
docker-compose logs -f
|
||
|
|
|
||
|
|
# Stop the container
|
||
|
|
docker-compose down
|
||
|
|
```
|
||
|
|
|
||
|
|
Access the application at: **http://localhost:12345**
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## PWA Deployment
|
||
|
|
|
||
|
|
### 1. Build for Production
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Build optimized production bundle
|
||
|
|
docker-compose build --no-cache
|
||
|
|
|
||
|
|
# Or build frontend separately
|
||
|
|
cd frontend
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Generate PWA Icons
|
||
|
|
|
||
|
|
Replace placeholder icons in `frontend/public/icons/` with actual icons:
|
||
|
|
|
||
|
|
**Required sizes:**
|
||
|
|
- 72x72, 96x96, 128x128, 144x144, 152x152, 192x192, 384x384, 512x512
|
||
|
|
|
||
|
|
**Tools:**
|
||
|
|
- [PWA Asset Generator](https://github.com/onderceylan/pwa-asset-generator)
|
||
|
|
- [RealFaviconGenerator](https://realfavicongenerator.net/)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install PWA asset generator
|
||
|
|
npm install -g pwa-asset-generator
|
||
|
|
|
||
|
|
# Generate icons from source image
|
||
|
|
pwa-asset-generator source-icon.png frontend/public/icons --icon-only --manifest frontend/public/manifest.json
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Android APK Build
|
||
|
|
|
||
|
|
#### Prerequisites
|
||
|
|
- Node.js 18+
|
||
|
|
- Android Studio or Capacitor CLI
|
||
|
|
|
||
|
|
#### Steps
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install Capacitor
|
||
|
|
npm install -g @capacitor/cli @capacitor/core @capacitor/android
|
||
|
|
|
||
|
|
# Initialize Capacitor in frontend directory
|
||
|
|
cd frontend
|
||
|
|
npx cap init StreamFlow tv.streamflow.app
|
||
|
|
|
||
|
|
# Add Android platform
|
||
|
|
npx cap add android
|
||
|
|
|
||
|
|
# Build frontend
|
||
|
|
npm run build
|
||
|
|
|
||
|
|
# Copy web assets to Android
|
||
|
|
npx cap copy android
|
||
|
|
|
||
|
|
# Open in Android Studio
|
||
|
|
npx cap open android
|
||
|
|
```
|
||
|
|
|
||
|
|
**In Android Studio:**
|
||
|
|
1. Build → Generate Signed Bundle / APK
|
||
|
|
2. Select APK
|
||
|
|
3. Create keystore (first time) or use existing
|
||
|
|
4. Build Release APK
|
||
|
|
5. APK will be in `frontend/android/app/build/outputs/apk/release/`
|
||
|
|
|
||
|
|
#### Alternative: Cordova Build
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install Cordova
|
||
|
|
npm install -g cordova
|
||
|
|
|
||
|
|
# Create Cordova project
|
||
|
|
cordova create streamflow tv.streamflow.app StreamFlow
|
||
|
|
|
||
|
|
# Copy built files to www/
|
||
|
|
cp -r frontend/dist/* streamflow/www/
|
||
|
|
|
||
|
|
# Add Android platform
|
||
|
|
cd streamflow
|
||
|
|
cordova platform add android
|
||
|
|
|
||
|
|
# Build APK
|
||
|
|
cordova build android --release
|
||
|
|
|
||
|
|
# Sign APK (optional)
|
||
|
|
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
|
||
|
|
-keystore my-release-key.keystore \
|
||
|
|
platforms/android/app/build/outputs/apk/release/app-release-unsigned.apk \
|
||
|
|
alias_name
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Linux AppImage Build
|
||
|
|
|
||
|
|
#### Prerequisites
|
||
|
|
- Node.js 18+
|
||
|
|
- Electron
|
||
|
|
- electron-builder
|
||
|
|
|
||
|
|
#### Steps
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install Electron globally
|
||
|
|
npm install -g electron electron-builder
|
||
|
|
|
||
|
|
# Create Electron wrapper
|
||
|
|
cd /home/iulian/projects/tv
|
||
|
|
mkdir electron-app
|
||
|
|
cd electron-app
|
||
|
|
|
||
|
|
# Initialize package.json
|
||
|
|
cat > package.json << 'EOF'
|
||
|
|
{
|
||
|
|
"name": "streamflow",
|
||
|
|
"version": "1.0.0",
|
||
|
|
"description": "IPTV Streaming Application",
|
||
|
|
"main": "main.js",
|
||
|
|
"scripts": {
|
||
|
|
"start": "electron .",
|
||
|
|
"build": "electron-builder --linux AppImage"
|
||
|
|
},
|
||
|
|
"build": {
|
||
|
|
"appId": "tv.streamflow.app",
|
||
|
|
"productName": "StreamFlow",
|
||
|
|
"linux": {
|
||
|
|
"target": ["AppImage"],
|
||
|
|
"category": "AudioVideo",
|
||
|
|
"icon": "../frontend/public/icons/icon-512x512.png"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"devDependencies": {
|
||
|
|
"electron": "^28.0.0",
|
||
|
|
"electron-builder": "^24.9.0"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Create main.js
|
||
|
|
cat > main.js << 'EOF'
|
||
|
|
const { app, BrowserWindow } = require('electron');
|
||
|
|
const path = require('path');
|
||
|
|
|
||
|
|
function createWindow() {
|
||
|
|
const mainWindow = new BrowserWindow({
|
||
|
|
width: 1280,
|
||
|
|
height: 720,
|
||
|
|
webPreferences: {
|
||
|
|
nodeIntegration: false,
|
||
|
|
contextIsolation: true
|
||
|
|
},
|
||
|
|
icon: path.join(__dirname, '../frontend/public/icons/icon-512x512.png')
|
||
|
|
});
|
||
|
|
|
||
|
|
// Load from Docker container
|
||
|
|
mainWindow.loadURL('http://localhost:12345');
|
||
|
|
|
||
|
|
// Uncomment for development
|
||
|
|
// mainWindow.webContents.openDevTools();
|
||
|
|
}
|
||
|
|
|
||
|
|
app.whenReady().then(createWindow);
|
||
|
|
|
||
|
|
app.on('window-all-closed', () => {
|
||
|
|
if (process.platform !== 'darwin') {
|
||
|
|
app.quit();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
app.on('activate', () => {
|
||
|
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||
|
|
createWindow();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
EOF
|
||
|
|
|
||
|
|
# Install dependencies
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# Build AppImage
|
||
|
|
npm run build
|
||
|
|
```
|
||
|
|
|
||
|
|
**Output:** `electron-app/dist/StreamFlow-1.0.0.AppImage`
|
||
|
|
|
||
|
|
**Run AppImage:**
|
||
|
|
```bash
|
||
|
|
chmod +x StreamFlow-1.0.0.AppImage
|
||
|
|
./StreamFlow-1.0.0.AppImage
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Testing PWA Features
|
||
|
|
|
||
|
|
### 1. Test Service Worker
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Start production server
|
||
|
|
docker-compose up -d
|
||
|
|
|
||
|
|
# Open browser dev tools
|
||
|
|
# Application tab → Service Workers
|
||
|
|
# Should see service-worker.js registered
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Test Offline Functionality
|
||
|
|
|
||
|
|
1. Open http://localhost:12345
|
||
|
|
2. Open DevTools → Network tab
|
||
|
|
3. Check "Offline" checkbox
|
||
|
|
4. Refresh page
|
||
|
|
5. Static assets should load from cache
|
||
|
|
|
||
|
|
### 3. Test Install Prompt
|
||
|
|
|
||
|
|
**Desktop:**
|
||
|
|
- Chrome/Edge: Click install icon in address bar
|
||
|
|
- Firefox: Menu → Install
|
||
|
|
|
||
|
|
**Mobile:**
|
||
|
|
- Chrome Android: "Add to Home Screen"
|
||
|
|
- iOS Safari: Share → Add to Home Screen
|
||
|
|
|
||
|
|
### 4. Lighthouse PWA Audit
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Install Lighthouse
|
||
|
|
npm install -g lighthouse
|
||
|
|
|
||
|
|
# Run audit
|
||
|
|
lighthouse http://localhost:12345 --view --preset=desktop
|
||
|
|
```
|
||
|
|
|
||
|
|
**Target scores:**
|
||
|
|
- Performance: 90+
|
||
|
|
- PWA: 100
|
||
|
|
- Accessibility: 90+
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Build Optimization
|
||
|
|
|
||
|
|
### 1. Reduce Bundle Size
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// vite.config.js optimizations
|
||
|
|
export default {
|
||
|
|
build: {
|
||
|
|
rollupOptions: {
|
||
|
|
output: {
|
||
|
|
manualChunks: {
|
||
|
|
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
|
||
|
|
'vendor-mui': ['@mui/material', '@emotion/react', '@emotion/styled'],
|
||
|
|
'vendor-utils': ['zustand', 'i18next', 'react-i18next']
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
chunkSizeWarningLimit: 600
|
||
|
|
}
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Enable Compression
|
||
|
|
|
||
|
|
```nginx
|
||
|
|
# Add to nginx.conf (if using nginx)
|
||
|
|
gzip on;
|
||
|
|
gzip_types text/css application/javascript application/json image/svg+xml;
|
||
|
|
gzip_min_length 1000;
|
||
|
|
|
||
|
|
# Brotli compression
|
||
|
|
brotli on;
|
||
|
|
brotli_types text/css application/javascript application/json;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Image Optimization
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Optimize PWA icons
|
||
|
|
npm install -g sharp-cli
|
||
|
|
|
||
|
|
# Convert to WebP
|
||
|
|
for file in frontend/public/icons/*.png; do
|
||
|
|
sharp -i "$file" -o "${file%.png}.webp"
|
||
|
|
done
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Security Hardening
|
||
|
|
|
||
|
|
### 1. HTTPS Setup (Production)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Generate SSL certificate
|
||
|
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||
|
|
-keyout ssl/nginx.key -out ssl/nginx.crt
|
||
|
|
|
||
|
|
# Update docker-compose.yml
|
||
|
|
services:
|
||
|
|
app:
|
||
|
|
ports:
|
||
|
|
- "12345:12345"
|
||
|
|
- "12346:12346" # HTTPS port
|
||
|
|
volumes:
|
||
|
|
- ./ssl:/app/ssl:ro
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Content Security Policy
|
||
|
|
|
||
|
|
Add to `frontend/index.html`:
|
||
|
|
```html
|
||
|
|
<meta http-equiv="Content-Security-Policy"
|
||
|
|
content="default-src 'self';
|
||
|
|
script-src 'self' 'unsafe-inline';
|
||
|
|
style-src 'self' 'unsafe-inline';
|
||
|
|
img-src 'self' data: https:;
|
||
|
|
connect-src 'self' http://localhost:12345">
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Rate Limiting
|
||
|
|
|
||
|
|
Already implemented in backend:
|
||
|
|
```javascript
|
||
|
|
// backend/server.js
|
||
|
|
const rateLimit = require('express-rate-limit');
|
||
|
|
|
||
|
|
const limiter = rateLimit({
|
||
|
|
windowMs: 15 * 60 * 1000, // 15 minutes
|
||
|
|
max: 100 // 100 requests per windowMs
|
||
|
|
});
|
||
|
|
|
||
|
|
app.use('/api/', limiter);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Debugging
|
||
|
|
|
||
|
|
### 1. Backend Logs
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# View live logs
|
||
|
|
docker-compose logs -f app
|
||
|
|
|
||
|
|
# Filter by level
|
||
|
|
docker-compose logs app | grep ERROR
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Frontend Development
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Run frontend dev server
|
||
|
|
cd frontend
|
||
|
|
npm run dev
|
||
|
|
|
||
|
|
# Opens at http://localhost:5173
|
||
|
|
# Hot reload enabled
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Database Inspection
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Access container
|
||
|
|
docker exec -it tv-app-1 sh
|
||
|
|
|
||
|
|
# Open SQLite database
|
||
|
|
sqlite3 /app/data/iptv.db
|
||
|
|
|
||
|
|
# View tables
|
||
|
|
.tables
|
||
|
|
|
||
|
|
# Query users
|
||
|
|
SELECT * FROM users;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Network Issues
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Test backend API
|
||
|
|
curl -X POST http://localhost:12345/api/auth/register \
|
||
|
|
-H "Content-Type: application/json" \
|
||
|
|
-d '{"username":"test","email":"test@test.com","password":"test123"}'
|
||
|
|
|
||
|
|
# Test health endpoint
|
||
|
|
curl http://localhost:12345/health
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Performance Tuning
|
||
|
|
|
||
|
|
### 1. Node.js Memory Optimization
|
||
|
|
|
||
|
|
```dockerfile
|
||
|
|
# Update Dockerfile
|
||
|
|
CMD ["node", "--max-old-space-size=512", "server.js"]
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Database Indexing
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Run in SQLite console
|
||
|
|
CREATE INDEX idx_channels_playlist ON channels(playlist_id);
|
||
|
|
CREATE INDEX idx_channels_group ON channels(group_title);
|
||
|
|
CREATE INDEX idx_epg_channel_time ON epg_programs(channel_id, start_time);
|
||
|
|
CREATE INDEX idx_favorites_user ON favorites(user_id);
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Caching Strategy
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Update service-worker.js for aggressive caching
|
||
|
|
const CACHE_NAME = 'streamflow-v1';
|
||
|
|
const CACHE_URLS = [
|
||
|
|
'/',
|
||
|
|
'/index.html',
|
||
|
|
'/assets/index.js',
|
||
|
|
'/assets/index.css',
|
||
|
|
// Add static assets
|
||
|
|
];
|
||
|
|
|
||
|
|
// Cache-first strategy for assets
|
||
|
|
self.addEventListener('fetch', (event) => {
|
||
|
|
if (event.request.url.includes('/assets/')) {
|
||
|
|
event.respondWith(
|
||
|
|
caches.match(event.request)
|
||
|
|
.then(response => response || fetch(event.request))
|
||
|
|
);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Continuous Deployment
|
||
|
|
|
||
|
|
### 1. GitHub Actions CI/CD
|
||
|
|
|
||
|
|
Create `.github/workflows/build.yml`:
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
name: Build & Deploy
|
||
|
|
|
||
|
|
on:
|
||
|
|
push:
|
||
|
|
branches: [main]
|
||
|
|
|
||
|
|
jobs:
|
||
|
|
build:
|
||
|
|
runs-on: ubuntu-latest
|
||
|
|
steps:
|
||
|
|
- uses: actions/checkout@v3
|
||
|
|
|
||
|
|
- name: Build Docker image
|
||
|
|
run: docker-compose build
|
||
|
|
|
||
|
|
- name: Run tests
|
||
|
|
run: docker-compose run app npm test
|
||
|
|
|
||
|
|
- name: Push to registry
|
||
|
|
run: |
|
||
|
|
docker tag tv-app:latest myregistry/tv-app:latest
|
||
|
|
docker push myregistry/tv-app:latest
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Auto-versioning
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Update version in package.json
|
||
|
|
npm version patch # 1.0.0 → 1.0.1
|
||
|
|
npm version minor # 1.0.0 → 1.1.0
|
||
|
|
npm version major # 1.0.0 → 2.0.0
|
||
|
|
|
||
|
|
# Rebuild with new version
|
||
|
|
docker-compose build
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Troubleshooting
|
||
|
|
|
||
|
|
### Common Issues
|
||
|
|
|
||
|
|
**Issue:** Port 12345 already in use
|
||
|
|
```bash
|
||
|
|
# Find process using port
|
||
|
|
sudo lsof -i :12345
|
||
|
|
|
||
|
|
# Kill process
|
||
|
|
kill -9 <PID>
|
||
|
|
```
|
||
|
|
|
||
|
|
**Issue:** Permission denied on data directory
|
||
|
|
```bash
|
||
|
|
# Fix permissions
|
||
|
|
sudo chown -R 1001:1001 backend/data
|
||
|
|
chmod 755 backend/data
|
||
|
|
```
|
||
|
|
|
||
|
|
**Issue:** Frontend not loading
|
||
|
|
```bash
|
||
|
|
# Rebuild frontend
|
||
|
|
cd frontend
|
||
|
|
rm -rf dist node_modules
|
||
|
|
npm install
|
||
|
|
npm run build
|
||
|
|
|
||
|
|
# Rebuild container
|
||
|
|
docker-compose build --no-cache
|
||
|
|
docker-compose up -d
|
||
|
|
```
|
||
|
|
|
||
|
|
**Issue:** Service worker not updating
|
||
|
|
```bash
|
||
|
|
# Clear browser cache
|
||
|
|
# In DevTools: Application → Clear storage → Clear site data
|
||
|
|
|
||
|
|
# Or update service worker version
|
||
|
|
# Edit frontend/public/service-worker.js
|
||
|
|
const CACHE_NAME = 'streamflow-v2'; // Increment version
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Production Deployment
|
||
|
|
|
||
|
|
### 1. Environment Variables
|
||
|
|
|
||
|
|
Create `.env` file:
|
||
|
|
```bash
|
||
|
|
NODE_ENV=production
|
||
|
|
PORT=12345
|
||
|
|
JWT_SECRET=your-secure-secret-here-change-this
|
||
|
|
DATABASE_PATH=/app/data/iptv.db
|
||
|
|
LOG_LEVEL=info
|
||
|
|
RATE_LIMIT_MAX=100
|
||
|
|
CORS_ORIGIN=https://yourdomain.com
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Docker Swarm Deployment
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Initialize swarm
|
||
|
|
docker swarm init
|
||
|
|
|
||
|
|
# Deploy stack
|
||
|
|
docker stack deploy -c docker-compose.yml streamflow
|
||
|
|
|
||
|
|
# Scale services
|
||
|
|
docker service scale streamflow_app=3
|
||
|
|
|
||
|
|
# Update service
|
||
|
|
docker service update --image tv-app:latest streamflow_app
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Kubernetes Deployment
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
# kubernetes/deployment.yaml
|
||
|
|
apiVersion: apps/v1
|
||
|
|
kind: Deployment
|
||
|
|
metadata:
|
||
|
|
name: streamflow
|
||
|
|
spec:
|
||
|
|
replicas: 3
|
||
|
|
selector:
|
||
|
|
matchLabels:
|
||
|
|
app: streamflow
|
||
|
|
template:
|
||
|
|
metadata:
|
||
|
|
labels:
|
||
|
|
app: streamflow
|
||
|
|
spec:
|
||
|
|
containers:
|
||
|
|
- name: streamflow
|
||
|
|
image: tv-app:latest
|
||
|
|
ports:
|
||
|
|
- containerPort: 12345
|
||
|
|
volumeMounts:
|
||
|
|
- name: data
|
||
|
|
mountPath: /app/data
|
||
|
|
volumes:
|
||
|
|
- name: data
|
||
|
|
persistentVolumeClaim:
|
||
|
|
claimName: streamflow-pvc
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Support
|
||
|
|
|
||
|
|
For issues or questions:
|
||
|
|
1. Check logs: `docker-compose logs -f`
|
||
|
|
2. Review error messages in browser console
|
||
|
|
3. Verify port 12345 is accessible
|
||
|
|
4. Ensure Docker has sufficient resources (2GB+ RAM)
|
||
|
|
|
||
|
|
**Happy Streaming! 🎬**
|