feat: initial release — SRT Streamer v1.0.0

Cross-platform Electron + React + FFmpeg desktop app for sending
multiple SRT streams simultaneously.

Features:
- Multiple simultaneous SRT output streams
- Video sources: desktop, window capture, cameras, capture cards
- Audio sources: microphones, system loopback, sound cards
- H.264 encoding with HW acceleration (NVENC/QSV/AMF/VideoToolbox)
- SRT modes: caller / listener / rendezvous
- Frame profile presets (4K, 1080p, 720p, 480p, 360p)
- Tolbek SRT receiver with configurable mode
- System tray: minimize-to-tray, exit confirmation dialog
- Portable build via electron-builder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
admin
2026-04-16 00:37:40 +03:00
commit 1f7dbc2a7d
25 changed files with 10548 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
/**
* Creates minimal placeholder PNG icons without any dependencies.
* Run: node assets/create-placeholder-icons.js
*/
const fs = require('fs')
const path = require('path')
// Minimal valid 16x16 PNG (dark blue background)
function createSimplePng(size) {
// Use a canvas-like approach with raw PNG data
// This creates a simple colored square PNG
const { createCanvas } = (() => {
try { return require('canvas') } catch { return null }
})() || {}
if (createCanvas) {
const canvas = createCanvas(size, size)
const ctx = canvas.getContext('2d')
// Background
ctx.fillStyle = '#1a1a2e'
const r = size * 0.19
ctx.beginPath()
ctx.moveTo(r, 0)
ctx.lineTo(size - r, 0)
ctx.quadraticCurveTo(size, 0, size, r)
ctx.lineTo(size, size - r)
ctx.quadraticCurveTo(size, size, size - r, size)
ctx.lineTo(r, size)
ctx.quadraticCurveTo(0, size, 0, size - r)
ctx.lineTo(0, r)
ctx.quadraticCurveTo(0, 0, r, 0)
ctx.closePath()
ctx.fill()
// Play triangle
const cx = size / 2, cy = size / 2
const s = size * 0.3
ctx.fillStyle = '#4f8ef7'
ctx.beginPath()
ctx.moveTo(cx - s * 0.5, cy - s * 0.6)
ctx.lineTo(cx + s * 0.7, cy)
ctx.lineTo(cx - s * 0.5, cy + s * 0.6)
ctx.closePath()
ctx.fill()
// Red dot
ctx.fillStyle = '#ef4444'
ctx.beginPath()
ctx.arc(size * 0.75, size * 0.25, size * 0.1, 0, Math.PI * 2)
ctx.fill()
return canvas.toBuffer('image/png')
}
// Fallback: minimal 1x1 PNG
return Buffer.from(
'89504e470d0a1a0a0000000d4948445200000001000000010802000000' +
'9001' + '2e00000000c4944415408d7626060600000000200014fd7181000000049454e44ae426082', 'hex'
)
}
const sizes = [
{ name: 'icon.png', size: 512 },
{ name: 'tray-icon.png', size: 32 }
]
for (const { name, size } of sizes) {
const buf = createSimplePng(size)
fs.writeFileSync(path.join(__dirname, name), buf)
console.log(`Created ${name}`)
}
+39
View File
@@ -0,0 +1,39 @@
/**
* Run with: node assets/generate-icons.js
* Requires: npm install sharp (dev only)
* Generates PNG icons from SVG for all platforms.
* If sharp is not available, falls back to copying a placeholder.
*/
const fs = require('fs')
const path = require('path')
async function generate() {
const svgPath = path.join(__dirname, 'icon.svg')
const svgData = fs.readFileSync(svgPath)
try {
const sharp = require('sharp')
// PNG 512x512
await sharp(svgData).resize(512, 512).png().toFile(path.join(__dirname, 'icon.png'))
console.log('icon.png generated')
// Tray icon 32x32
await sharp(svgData).resize(32, 32).png().toFile(path.join(__dirname, 'tray-icon.png'))
console.log('tray-icon.png generated')
console.log('Done. For ICO/ICNS, use electron-icon-builder or convert manually.')
} catch (e) {
console.log('sharp not available, creating placeholder PNG...')
// Create a minimal 1x1 placeholder PNG (will work as fallback)
const minPng = Buffer.from(
'89504e470d0a1a0a0000000d49484452000000010000000108020000009001' +
'2e000000000c4944415408d76360f8cfc00000000200017e21bc330000000049454e44ae426082',
'hex'
)
fs.writeFileSync(path.join(__dirname, 'icon.png'), minPng)
fs.writeFileSync(path.join(__dirname, 'tray-icon.png'), minPng)
console.log('Placeholder icons created.')
}
}
generate().catch(console.error)
+22
View File
@@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" width="256" height="256">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#1a1a2e"/>
<stop offset="100%" stop-color="#16213e"/>
</linearGradient>
<linearGradient id="accent" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#4f8ef7"/>
<stop offset="100%" stop-color="#22c55e"/>
</linearGradient>
</defs>
<rect width="256" height="256" rx="48" fill="url(#bg)"/>
<!-- Signal waves -->
<path d="M60 128 Q60 68 128 68 Q196 68 196 128 Q196 188 128 188 Q60 188 60 128" fill="none" stroke="#4f8ef7" stroke-width="8" stroke-opacity="0.3" stroke-dasharray="8 6"/>
<!-- Play triangle -->
<polygon points="100,90 172,128 100,166" fill="url(#accent)" opacity="0.9"/>
<!-- Live dot -->
<circle cx="188" cy="68" r="18" fill="#ef4444"/>
<circle cx="188" cy="68" r="10" fill="#ffffff"/>
<!-- SRT text -->
<text x="128" y="220" font-family="Arial,sans-serif" font-size="22" font-weight="700" fill="#94a3b8" text-anchor="middle" letter-spacing="4">SRT</text>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB