Improve camera model search with per-model ranking and two-stage loading
- Split camera results into individual models (Brand: Model format) - Add model-specific relevance scoring for better search results - Implement two-stage autocomplete: 10 results immediately, 50 after 1 second - Filter out "Other" models from search results - Sort models by relevance score (exact matches first) - Add auto.json brand for automatic detection fallback 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
export class FrigateGenerator {
|
||||
static generate(stream) {
|
||||
// For non-RTSP streams, suggest using Go2RTC
|
||||
if (stream.type !== 'FFMPEG' || stream.protocol !== 'rtsp') {
|
||||
return `# This stream type requires Go2RTC proxy\n\n` +
|
||||
`# This ${stream.type} stream is not natively supported by Frigate.\n` +
|
||||
`# Please use Go2RTC to convert it to RTSP first.\n\n` +
|
||||
`# Steps:\n` +
|
||||
`# 1. Add this stream to your Go2RTC configuration\n` +
|
||||
`# 2. Use the Go2RTC RTSP endpoint in Frigate\n` +
|
||||
`# 3. Example: rtsp://localhost:8554/camera_stream_0`;
|
||||
}
|
||||
|
||||
// Generate RTSP config for Frigate
|
||||
const cameraName = this.generateCameraName(stream);
|
||||
const config = [];
|
||||
|
||||
config.push(`cameras:`);
|
||||
config.push(` ${cameraName}:`);
|
||||
config.push(` ffmpeg:`);
|
||||
config.push(` inputs:`);
|
||||
config.push(` - path: ${stream.url}`);
|
||||
config.push(` roles:`);
|
||||
config.push(` - detect`);
|
||||
config.push(` - record`);
|
||||
|
||||
if (stream.resolution) {
|
||||
config.push(` detect:`);
|
||||
const [width, height] = stream.resolution.split('x').map(Number);
|
||||
if (width && height) {
|
||||
config.push(` width: ${width}`);
|
||||
config.push(` height: ${height}`);
|
||||
}
|
||||
}
|
||||
|
||||
return config.join('\n');
|
||||
}
|
||||
|
||||
static generateCameraName(stream) {
|
||||
try {
|
||||
const urlObj = new URL(stream.url);
|
||||
const ip = urlObj.hostname.replace(/\./g, '_').replace(/:/g, '_');
|
||||
return `camera_${ip}`;
|
||||
} catch (e) {
|
||||
return 'camera';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
export class Go2RTCGenerator {
|
||||
static generate(stream) {
|
||||
const streamName = this.generateStreamName(stream);
|
||||
|
||||
switch (stream.type) {
|
||||
case 'FFMPEG':
|
||||
if (stream.protocol === 'rtsp') {
|
||||
return this.generateRTSP(streamName, stream);
|
||||
}
|
||||
break;
|
||||
case 'JPEG':
|
||||
return this.generateJPEG(streamName, stream);
|
||||
case 'MJPEG':
|
||||
return this.generateMJPEG(streamName, stream);
|
||||
case 'HTTP_VIDEO':
|
||||
return this.generateHTTPVideo(streamName, stream);
|
||||
case 'HLS':
|
||||
return this.generateHLS(streamName, stream);
|
||||
case 'ONVIF':
|
||||
return `# ONVIF Device Service\n# This is a device management endpoint, not a stream\n# URL: ${stream.url}`;
|
||||
default:
|
||||
return this.generateRTSP(streamName, stream);
|
||||
}
|
||||
}
|
||||
|
||||
static generateStreamName(stream) {
|
||||
try {
|
||||
const urlObj = new URL(stream.url);
|
||||
const ip = urlObj.hostname.replace(/\./g, '_').replace(/:/g, '_');
|
||||
return `${ip}_0`;
|
||||
} catch (e) {
|
||||
return 'camera_stream_0';
|
||||
}
|
||||
}
|
||||
|
||||
static generateRTSP(streamName, stream) {
|
||||
return `streams:\n '${streamName}':\n - ${stream.url}`;
|
||||
}
|
||||
|
||||
static generateJPEG(streamName, stream) {
|
||||
const framerate = 10;
|
||||
const ffmpegCmd = [
|
||||
'exec:ffmpeg',
|
||||
'-loglevel quiet',
|
||||
'-f image2',
|
||||
'-loop 1',
|
||||
`-framerate ${framerate}`,
|
||||
`-i ${stream.url}`,
|
||||
'-c:v libx264',
|
||||
'-preset ultrafast',
|
||||
'-tune zerolatency',
|
||||
'-g 20',
|
||||
'-f rtsp {output}'
|
||||
].join(' ');
|
||||
|
||||
return `streams:\n '${streamName}':\n - ${ffmpegCmd}`;
|
||||
}
|
||||
|
||||
static generateMJPEG(streamName, stream) {
|
||||
const ffmpegCmd = [
|
||||
'exec:ffmpeg',
|
||||
'-loglevel quiet',
|
||||
`-i ${stream.url}`,
|
||||
'-c:v copy',
|
||||
'-f rtsp {output}'
|
||||
].join(' ');
|
||||
|
||||
return `streams:\n '${streamName}':\n - ${ffmpegCmd}`;
|
||||
}
|
||||
|
||||
static generateHTTPVideo(streamName, stream) {
|
||||
const ffmpegCmd = [
|
||||
'exec:ffmpeg',
|
||||
'-loglevel quiet',
|
||||
`-i ${stream.url}`,
|
||||
'-c:v copy',
|
||||
'-c:a copy',
|
||||
'-f rtsp {output}'
|
||||
].join(' ');
|
||||
|
||||
return `streams:\n '${streamName}':\n - ${ffmpegCmd}`;
|
||||
}
|
||||
|
||||
static generateHLS(streamName, stream) {
|
||||
return `streams:\n '${streamName}':\n - ${stream.url}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user