This commit is contained in:
parent
1acd1c0cab
commit
7cd5e80468
23 changed files with 988 additions and 5 deletions
178
music.go
Normal file
178
music.go
Normal file
|
@ -0,0 +1,178 @@
|
|||
// music.go - Central music search handler
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MusicSearchEngine struct {
|
||||
Name string
|
||||
Func func(query string, page int) ([]MusicResult, error)
|
||||
}
|
||||
|
||||
var (
|
||||
musicSearchEngines []MusicSearchEngine
|
||||
cacheMutex = &sync.Mutex{}
|
||||
)
|
||||
|
||||
var allMusicSearchEngines = []MusicSearchEngine{
|
||||
{Name: "SoundCloud", Func: SearchSoundCloud},
|
||||
{Name: "YouTube", Func: SearchMusicViaPiped},
|
||||
{Name: "Bandcamp", Func: SearchBandcamp},
|
||||
//{Name: "Spotify", Func: SearchSpotify},
|
||||
}
|
||||
|
||||
func initMusicEngines() {
|
||||
// Initialize with all engines if no specific config
|
||||
musicSearchEngines = allMusicSearchEngines
|
||||
}
|
||||
|
||||
func handleMusicSearch(w http.ResponseWriter, settings UserSettings, query string, page int) {
|
||||
start := time.Now()
|
||||
|
||||
cacheKey := CacheKey{
|
||||
Query: query,
|
||||
Page: page,
|
||||
Type: "music",
|
||||
Lang: settings.SearchLanguage,
|
||||
Safe: settings.SafeSearch == "active",
|
||||
}
|
||||
|
||||
var results []MusicResult
|
||||
|
||||
if cached, found := resultsCache.Get(cacheKey); found {
|
||||
if musicResults, ok := convertCacheToMusicResults(cached); ok {
|
||||
results = musicResults
|
||||
}
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
results = fetchMusicResults(query, page)
|
||||
if len(results) > 0 {
|
||||
resultsCache.Set(cacheKey, convertMusicResultsToCache(results))
|
||||
}
|
||||
}
|
||||
|
||||
go prefetchMusicPages(query, page)
|
||||
|
||||
elapsed := time.Since(start) // Calculate duration
|
||||
fetched := fmt.Sprintf("%.2f %s", elapsed.Seconds(), Translate("seconds"))
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Results": results,
|
||||
"Query": query,
|
||||
"Page": page,
|
||||
"HasPrevPage": page > 1,
|
||||
"HasNextPage": len(results) >= 10, // Default page size
|
||||
"MusicServices": getMusicServiceNames(),
|
||||
"CurrentService": "all", // Default service
|
||||
"Theme": settings.Theme,
|
||||
"IsThemeDark": settings.IsThemeDark,
|
||||
"Trans": Translate,
|
||||
"Fetched": fetched,
|
||||
}
|
||||
|
||||
renderTemplate(w, "music.html", data)
|
||||
}
|
||||
|
||||
// Helper to get music service names
|
||||
func getMusicServiceNames() []string {
|
||||
names := make([]string, len(allMusicSearchEngines))
|
||||
for i, engine := range allMusicSearchEngines {
|
||||
names[i] = engine.Name
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func convertMusicResultsToCache(results []MusicResult) []SearchResult {
|
||||
cacheResults := make([]SearchResult, len(results))
|
||||
for i, r := range results {
|
||||
cacheResults[i] = r
|
||||
}
|
||||
return cacheResults
|
||||
}
|
||||
|
||||
func convertCacheToMusicResults(cached []SearchResult) ([]MusicResult, bool) {
|
||||
results := make([]MusicResult, 0, len(cached))
|
||||
for _, item := range cached {
|
||||
if musicResult, ok := item.(MusicResult); ok {
|
||||
results = append(results, musicResult)
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return results, true
|
||||
}
|
||||
|
||||
func fetchMusicResults(query string, page int) []MusicResult {
|
||||
var results []MusicResult
|
||||
resultsChan := make(chan []MusicResult, len(musicSearchEngines))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, engine := range musicSearchEngines {
|
||||
wg.Add(1)
|
||||
go func(e MusicSearchEngine) {
|
||||
defer wg.Done()
|
||||
res, err := e.Func(query, page)
|
||||
if err == nil && len(res) > 0 {
|
||||
resultsChan <- res
|
||||
}
|
||||
}(engine)
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(resultsChan)
|
||||
}()
|
||||
|
||||
for res := range resultsChan {
|
||||
results = append(results, res...)
|
||||
if len(results) >= 50 { // Default max results
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return deduplicateResults(results)
|
||||
}
|
||||
|
||||
func prefetchMusicPages(query string, currentPage int) {
|
||||
for _, page := range []int{currentPage - 1, currentPage + 1} {
|
||||
if page < 1 {
|
||||
continue
|
||||
}
|
||||
cacheKey := CacheKey{
|
||||
Query: query,
|
||||
Page: page,
|
||||
Type: "music",
|
||||
}
|
||||
if _, found := resultsCache.Get(cacheKey); !found {
|
||||
go fetchMusicResults(query, page)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func deduplicateResults(results []MusicResult) []MusicResult {
|
||||
seen := make(map[string]bool)
|
||||
var unique []MusicResult
|
||||
|
||||
for _, res := range results {
|
||||
if !seen[res.URL] {
|
||||
seen[res.URL] = true
|
||||
unique = append(unique, res)
|
||||
}
|
||||
}
|
||||
return unique
|
||||
}
|
||||
|
||||
// func generatePlayerHTML(result MusicResult) template.HTML {
|
||||
// if result.IframeSrc != "" {
|
||||
// return template.HTML(fmt.Sprintf(
|
||||
// `<iframe width="100%%" height="166" scrolling="no" frameborder="no" src="%s"></iframe>`,
|
||||
// result.IframeSrc,
|
||||
// ))
|
||||
// }
|
||||
// return template.HTML("")
|
||||
// }
|
Loading…
Add table
Add a link
Reference in a new issue