basic map results + improved fetching from piped

This commit is contained in:
partisan 2024-04-15 22:34:50 +02:00
parent 1efca320c8
commit 6c9ec56327
9 changed files with 239 additions and 20 deletions

102
video.go
View file

@ -8,10 +8,30 @@ import (
"net/http"
"net/url"
"strconv"
"sync"
"time"
)
const PIPED_INSTANCE = "pipedapi.kavin.rocks"
const retryDuration = 12 * time.Hour // Retry duration for unresponding piped instances
var (
pipedInstances = []string{
"pipedapi.kavin.rocks",
"api.piped.yt",
"pipedapi.moomoo.me",
"pipedapi.darkness.services",
"piped-api.hostux.net",
"pipedapi.syncpundit.io",
"piped-api.cfe.re",
"pipedapi.in.projectsegfau.lt",
"piapi.ggtyler.dev",
"piped-api.codespace.cz",
"pipedapi.coldforge.xyz",
"pipedapi.osphost.fi",
}
disabledInstances = make(map[string]bool)
mu sync.Mutex
)
// VideoResult reflects the structured data for a video result
type VideoResult struct {
@ -71,24 +91,76 @@ func formatDuration(seconds int) string {
return fmt.Sprintf("%02d:%02d", minutes, seconds)
}
// makeHTMLRequest fetches search results from the Piped API, similarly to the Python `makeHTMLRequest`
func init() {
go checkDisabledInstancesPeriodically()
}
func checkDisabledInstancesPeriodically() {
checkAndReactivateInstances() // Initial immediate check
ticker := time.NewTicker(retryDuration)
defer ticker.Stop()
for {
select {
case <-ticker.C:
checkAndReactivateInstances()
}
}
}
func checkAndReactivateInstances() {
mu.Lock()
defer mu.Unlock()
for instance, isDisabled := range disabledInstances {
if isDisabled {
// Check if the instance is available again
if testInstanceAvailability(instance) {
log.Printf("Instance %s is now available and reactivated.", instance)
delete(disabledInstances, instance)
} else {
log.Printf("Instance %s is still not available.", instance)
}
}
}
}
func testInstanceAvailability(instance string) bool {
resp, err := http.Get(fmt.Sprintf("https://%s/search?q=%s&filter=all", instance, url.QueryEscape("test")))
if err != nil || resp.StatusCode != http.StatusOK {
return false
}
return true
}
func makeHTMLRequest(query string) (*VideoAPIResponse, error) {
resp, err := http.Get(fmt.Sprintf("https://%s/search?q=%s&filter=all", PIPED_INSTANCE, url.QueryEscape(query)))
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
var lastError error
mu.Lock()
defer mu.Unlock()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
for _, instance := range pipedInstances {
if disabledInstances[instance] {
continue // Skip this instance because it's still disabled
}
var apiResp VideoAPIResponse
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
return nil, fmt.Errorf("error decoding response: %w", err)
}
url := fmt.Sprintf("https://%s/search?q=%s&filter=all", instance, url.QueryEscape(query))
resp, err := http.Get(url)
if err != nil || resp.StatusCode != http.StatusOK {
log.Printf("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)
continue
}
return &apiResp, nil
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)
continue
}
return &apiResp, nil
}
return nil, fmt.Errorf("all instances failed, last error: %v", lastError)
}
func videoSearchEndpointHandler(w http.ResponseWriter, r *http.Request) {