Fix SSE stream discovery and add ESLint for WebUI
JavaScript fixes: - Fix Invalid URL error in stream-discovery.js by adding window.location.origin as base URL - Fix SSE race condition: ensure all stream_found events sent before complete event - Comment unused eventType variable in stream-discovery.js - Comment unused FrigateGenerator import in config-panel.js - Fix quote style (double to single quotes) Go fixes: - Add sync.WaitGroup for result collector to prevent premature SSE closure - Add logging for stream_found events - Fix ERR_INCOMPLETE_CHUNKED_ENCODING by waiting for all streams to be sent ESLint setup: - Add ESLint v8.57.1 with .eslintrc.cjs config for ES2022 modules - Add npm scripts for lint and lint:fix - Update .gitignore for node_modules and package-lock.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -43,4 +43,8 @@ temp/
|
|||||||
*_output.txt
|
*_output.txt
|
||||||
|
|
||||||
# Configuration (user-specific)
|
# Configuration (user-specific)
|
||||||
strix.yaml
|
strix.yaml
|
||||||
|
|
||||||
|
# Node.js / NPM
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
@@ -434,10 +434,15 @@ func (s *Scanner) testStreamsConcurrently(ctx context.Context, streams []models.
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Start result collector
|
// Start result collector
|
||||||
|
var collectorWg sync.WaitGroup
|
||||||
|
collectorWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer collectorWg.Done()
|
||||||
for stream := range streamsChan {
|
for stream := range streamsChan {
|
||||||
result.Streams = append(result.Streams, stream)
|
result.Streams = append(result.Streams, stream)
|
||||||
|
|
||||||
|
s.logger.Info("sending stream_found event", "url", stream.URL, "type", stream.Type)
|
||||||
|
|
||||||
// Send to SSE
|
// Send to SSE
|
||||||
_ = streamWriter.SendJSON("stream_found", map[string]interface{}{
|
_ = streamWriter.SendJSON("stream_found", map[string]interface{}{
|
||||||
"stream": stream,
|
"stream": stream,
|
||||||
@@ -522,6 +527,9 @@ TestLoop:
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(streamsChan)
|
close(streamsChan)
|
||||||
|
|
||||||
|
// Wait for result collector to finish processing all streams
|
||||||
|
collectorWg.Wait()
|
||||||
|
|
||||||
// Update final counts
|
// Update final counts
|
||||||
result.TotalTested = int(atomic.LoadInt32(&tested))
|
result.TotalTested = int(atomic.LoadInt32(&tested))
|
||||||
result.TotalFound = int(atomic.LoadInt32(&found))
|
result.TotalFound = int(atomic.LoadInt32(&found))
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2021: true,
|
||||||
|
},
|
||||||
|
extends: 'eslint:recommended',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2022,
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
EventSource: 'readonly',
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'no-unused-vars': 'warn',
|
||||||
|
'no-undef': 'error',
|
||||||
|
'no-console': 'off', // Allow console for debugging
|
||||||
|
'semi': ['error', 'always'],
|
||||||
|
'quotes': ['warn', 'single', { avoidEscape: true }],
|
||||||
|
'no-var': 'error',
|
||||||
|
'prefer-const': 'warn',
|
||||||
|
'eqeqeq': ['error', 'always'],
|
||||||
|
'no-unreachable': 'error',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "webui",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"lint": "eslint web/js/**/*.js",
|
||||||
|
"lint:fix": "eslint web/js/**/*.js --fix"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^8.57.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ export class StreamDiscoveryAPI {
|
|||||||
discover(request, callbacks) {
|
discover(request, callbacks) {
|
||||||
this.close();
|
this.close();
|
||||||
|
|
||||||
const url = new URL(`${this.baseURL}/api/v1/streams/discover`);
|
const url = new URL(`${this.baseURL}/api/v1/streams/discover`, window.location.origin);
|
||||||
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -39,7 +39,8 @@ export class StreamDiscoveryAPI {
|
|||||||
|
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (line.startsWith('event:')) {
|
if (line.startsWith('event:')) {
|
||||||
const eventType = line.substring(6).trim();
|
// Parse event type (not currently used, but available for future features)
|
||||||
|
// const eventType = line.substring(6).trim();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Go2RTCGenerator } from '../config-generators/go2rtc/index.js';
|
import { Go2RTCGenerator } from '../config-generators/go2rtc/index.js';
|
||||||
import { FrigateGenerator } from '../config-generators/frigate/index.js';
|
// import { FrigateGenerator } from '../config-generators/frigate/index.js'; // Reserved for future use
|
||||||
|
|
||||||
export class ConfigPanel {
|
export class ConfigPanel {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class StreamCarousel {
|
|||||||
<div class="stream-url">${this.truncateURL(stream.url)}</div>
|
<div class="stream-url">${this.truncateURL(stream.url)}</div>
|
||||||
${stream.resolution ? `<div class="stream-meta">Resolution: ${stream.resolution}</div>` : ''}
|
${stream.resolution ? `<div class="stream-meta">Resolution: ${stream.resolution}</div>` : ''}
|
||||||
${stream.codec ? `<div class="stream-meta">Codec: ${stream.codec}${stream.fps ? ` • ${stream.fps} fps` : ''}${stream.bitrate ? ` • ${Math.round(stream.bitrate / 1000)} Kbps` : ''}</div>` : ''}
|
${stream.codec ? `<div class="stream-meta">Codec: ${stream.codec}${stream.fps ? ` • ${stream.fps} fps` : ''}${stream.bitrate ? ` • ${Math.round(stream.bitrate / 1000)} Kbps` : ''}</div>` : ''}
|
||||||
${stream.has_audio ? `<div class="stream-meta">Audio: Yes</div>` : ''}
|
${stream.has_audio ? '<div class="stream-meta">Audio: Yes</div>' : ''}
|
||||||
<div class="stream-actions">
|
<div class="stream-actions">
|
||||||
<button class="btn btn-primary btn-use" data-index="${index}">Use Stream</button>
|
<button class="btn btn-primary btn-use" data-index="${index}">Use Stream</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user