Fix URL parameter replacement logic to preserve literal values

This commit is contained in:
eduard256
2025-11-05 23:20:44 +03:00
parent a5c769dd6c
commit 12dd7735ad
+20 -54
View File
@@ -1,6 +1,7 @@
package stream package stream
import ( import (
"encoding/base64"
"fmt" "fmt"
"net/url" "net/url"
"regexp" "regexp"
@@ -56,6 +57,8 @@ func (b *Builder) BuildURL(entry models.CameraEntry, ctx BuildContext) string {
if ctx.Height == 0 { if ctx.Height == 0 {
ctx.Height = 480 ctx.Height = 480
} }
// NOTE: Channel default is 0 - will only be used for [CHANNEL] placeholder replacement
// Literal channel values in URLs (like "channel=1") are preserved as-is
// Use entry's port if not specified // Use entry's port if not specified
if ctx.Port == 0 { if ctx.Port == 0 {
@@ -163,6 +166,12 @@ func (b *Builder) BuildURL(entry models.CameraEntry, ctx BuildContext) string {
func (b *Builder) replacePlaceholders(urlPath string, ctx BuildContext) string { func (b *Builder) replacePlaceholders(urlPath string, ctx BuildContext) string {
result := urlPath result := urlPath
// Generate base64 auth for [AUTH] placeholder
auth := ""
if ctx.Username != "" && ctx.Password != "" {
auth = base64.StdEncoding.EncodeToString([]byte(ctx.Username + ":" + ctx.Password))
}
// Common placeholders // Common placeholders
replacements := map[string]string{ replacements := map[string]string{
"[CHANNEL]": strconv.Itoa(ctx.Channel), "[CHANNEL]": strconv.Itoa(ctx.Channel),
@@ -187,6 +196,8 @@ func (b *Builder) replacePlaceholders(urlPath string, ctx BuildContext) string {
"[ip]": ctx.IP, "[ip]": ctx.IP,
"[PORT]": strconv.Itoa(ctx.Port), "[PORT]": strconv.Itoa(ctx.Port),
"[port]": strconv.Itoa(ctx.Port), "[port]": strconv.Itoa(ctx.Port),
"[AUTH]": auth, // base64(username:password) for basic auth
"[auth]": auth,
"[TOKEN]": "", // Empty for now "[TOKEN]": "", // Empty for now
"[token]": "", "[token]": "",
} }
@@ -196,41 +207,12 @@ func (b *Builder) replacePlaceholders(urlPath string, ctx BuildContext) string {
result = strings.ReplaceAll(result, placeholder, value) result = strings.ReplaceAll(result, placeholder, value)
} }
// Handle {var} style placeholders // Handle query parameter placeholders (only for auth params)
result = b.replaceVarPlaceholders(result, ctx)
// Handle query parameter placeholders
result = b.replaceQueryParams(result, ctx) result = b.replaceQueryParams(result, ctx)
return result return result
} }
// replaceVarPlaceholders replaces {var} style placeholders
func (b *Builder) replaceVarPlaceholders(urlPath string, ctx BuildContext) string {
varPattern := regexp.MustCompile(`\{([^}]+)\}`)
return varPattern.ReplaceAllStringFunc(urlPath, func(match string) string {
key := strings.Trim(match, "{}")
switch strings.ToLower(key) {
case "username", "user":
return ctx.Username
case "password", "pass", "pwd":
return ctx.Password
case "ip":
return ctx.IP
case "port":
return strconv.Itoa(ctx.Port)
case "channel", "chn", "ch":
return strconv.Itoa(ctx.Channel)
case "width":
return strconv.Itoa(ctx.Width)
case "height":
return strconv.Itoa(ctx.Height)
default:
return match // Keep original if not recognized
}
})
}
// replaceQueryParams handles query parameter replacements // replaceQueryParams handles query parameter replacements
func (b *Builder) replaceQueryParams(urlPath string, ctx BuildContext) string { func (b *Builder) replaceQueryParams(urlPath string, ctx BuildContext) string {
@@ -249,24 +231,17 @@ func (b *Builder) replaceQueryParams(urlPath string, ctx BuildContext) string {
return urlPath return urlPath
} }
// Replace known parameter values // ONLY replace authentication parameters
// DO NOT replace channel, width, height - they should stay as-is from URL patterns
for key := range params { for key := range params {
lowerKey := strings.ToLower(key) lowerKey := strings.ToLower(key)
// Check if this is a known parameter from our list switch lowerKey {
if b.isKnownParameter(lowerKey) { case "user", "username", "usr", "loginuse":
switch lowerKey { params.Set(key, ctx.Username)
case "user", "username", "usr", "loginuse": case "password", "pass", "pwd", "loginpas", "passwd":
params.Set(key, ctx.Username) params.Set(key, ctx.Password)
case "password", "pass", "pwd", "loginpas", "passwd": // Removed: channel, width, height replacements - they were breaking working URLs
params.Set(key, ctx.Password)
case "channel", "chn", "ch":
params.Set(key, strconv.Itoa(ctx.Channel))
case "width":
params.Set(key, strconv.Itoa(ctx.Width))
case "height":
params.Set(key, strconv.Itoa(ctx.Height))
}
} }
} }
@@ -274,15 +249,6 @@ func (b *Builder) replaceQueryParams(urlPath string, ctx BuildContext) string {
return basePath + "?" + params.Encode() return basePath + "?" + params.Encode()
} }
// isKnownParameter checks if a parameter is in our known list
func (b *Builder) isKnownParameter(param string) bool {
for _, known := range b.queryParams {
if strings.ToLower(known) == param {
return true
}
}
return false
}
// hasAuthenticationParams checks if URL contains auth parameters // hasAuthenticationParams checks if URL contains auth parameters
func (b *Builder) hasAuthenticationParams(urlPath string) bool { func (b *Builder) hasAuthenticationParams(urlPath string) bool {