Improve hot start by preselecting working video search instance
Some checks are pending
Run Integration Tests / test (push) Waiting to run

This commit is contained in:
partisan 2025-06-10 19:33:26 +02:00
parent 1ec633470b
commit 8f31f0b2eb
3 changed files with 77 additions and 18 deletions

View file

@ -12,6 +12,7 @@ import (
const retryDuration = 12 * time.Hour // Retry duration for unresponding piped instances
var (
preferredInstance string
pipedInstances = []string{}
disabledInstances = make(map[string]bool)
mu sync.Mutex
@ -19,6 +20,8 @@ var (
func initPipedInstances() {
pipedInstances = config.MetaSearch.Video
go checkDisabledInstancesPeriodically()
go selectInitialPipedInstance()
}
// VideoAPIResponse matches the structure of the JSON response from the Piped API
@ -67,10 +70,6 @@ func formatDuration(seconds int) string {
return fmt.Sprintf("%02d:%02d", minutes, seconds)
}
func init() {
go checkDisabledInstancesPeriodically()
}
func checkDisabledInstancesPeriodically() {
checkAndReactivateInstances() // Initial immediate check
ticker := time.NewTicker(retryDuration)
@ -81,6 +80,28 @@ func checkDisabledInstancesPeriodically() {
}
}
func selectInitialPipedInstance() {
for _, inst := range pipedInstances {
if testInstanceAvailability(inst) {
mu.Lock()
preferredInstance = inst
mu.Unlock()
printInfo("Selected preferred piped instance: %s", inst)
return
}
}
printWarn("No available piped instances found during initial scan.")
}
func disableInstance(inst string) {
mu.Lock()
defer mu.Unlock()
disabledInstances[inst] = true
if preferredInstance == inst {
preferredInstance = ""
}
}
func checkAndReactivateInstances() {
mu.Lock()
defer mu.Unlock()
@ -107,32 +128,55 @@ func testInstanceAvailability(instance string) bool {
}
func makeHTMLRequest(query, safe, lang string, page int) (*VideoAPIResponse, error) {
mu.Lock()
instance := preferredInstance
mu.Unlock()
if instance != "" && !disabledInstances[instance] {
url := fmt.Sprintf("https://%s/search?q=%s&filter=all&safe=%s&lang=%s&page=%d",
instance, url.QueryEscape(query), safe, lang, page)
resp, err := http.Get(url)
if err == nil && resp.StatusCode == http.StatusOK {
defer resp.Body.Close()
var apiResp VideoAPIResponse
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err == nil {
return &apiResp, nil
}
}
printWarn("Preferred instance %s failed, falling back to other instances", instance)
disableInstance(instance)
}
// Fallback loop
var lastError error
mu.Lock()
defer mu.Unlock()
for _, instance := range pipedInstances {
if disabledInstances[instance] {
continue // Skip this instance because it's still disabled
for _, inst := range pipedInstances {
if disabledInstances[inst] {
continue
}
url := fmt.Sprintf("https://%s/search?q=%s&filter=all&safe=%s&lang=%s&page=%d", instance, url.QueryEscape(query), safe, lang, page)
url := fmt.Sprintf("https://%s/search?q=%s&filter=all&safe=%s&lang=%s&page=%d",
inst, url.QueryEscape(query), safe, lang, page)
resp, err := http.Get(url)
if err != nil || resp.StatusCode != http.StatusOK {
printInfo("Disabling instance %s due to error or status code: %v", instance, err)
disabledInstances[instance] = true
lastError = fmt.Errorf("error making request to %s: %w", instance, err)
printInfo("Disabling instance %s due to error or status code: %v", inst, err)
disabledInstances[inst] = true
lastError = fmt.Errorf("error from %s: %w", inst, err)
continue
}
defer resp.Body.Close()
var apiResp VideoAPIResponse
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
lastError = fmt.Errorf("error decoding response from %s: %w", instance, err)
lastError = fmt.Errorf("decode error from %s: %w", inst, err)
continue
}
// Store new preferred instance
preferredInstance = inst
return &apiResp, nil
}
return nil, fmt.Errorf("all instances failed, last error: %v", lastError)
}