package main import ( "fmt" "log" "os" "path/filepath" "strings" "sync" "time" "github.com/dhowden/tag" "github.com/google/uuid" ) type Episode struct { Title string File string Cover string PubDate string Artist string Size int64 } var ( lastMod time.Time rssLock sync.Mutex ) func generateUUIDFromString(input string) uuid.UUID { namespace := uuid.NameSpaceDNS // Namespace fisso per consistenza return uuid.NewSHA1(namespace, []byte(input)) } func generateRSS() error { rssLock.Lock() defer rssLock.Unlock() episodes, err := scanEpisodes() if err != nil { return err } rss := fmt.Sprintf(` %s %s %s`, podTitle, podTitle, baseURL) for _, ep := range episodes { rss += fmt.Sprintf(` %s %s `, ep.Title, baseURL, filepath.Base(ep.File), ep.Size, ep.PubDate) if ep.Cover != "" { rss += fmt.Sprintf(``, baseURL, ep.Cover) } if ep.Artist != "" { rss += fmt.Sprintf(` %s`, ep.Artist) } rss += fmt.Sprintf(`%s/audio/%s`, baseURL, filepath.Base(ep.File)) rss += fmt.Sprintf(`%s`, generateUUIDFromString(ep.Title).String()) rss += fmt.Sprintf(`%s`, ep.Title) rss += "\n " } rss += "\n\n" return os.WriteFile("feed.xml", []byte(rss), 0644) } func scanEpisodes() ([]Episode, error) { var episodes []Episode err := filepath.Walk(audioDir, func(path string, info os.FileInfo, err error) error { if err != nil || info.IsDir() || !strings.HasSuffix(strings.ToLower(path), ".mp3") { return nil } file, err := os.Open(path) if err != nil { return err } defer file.Close() meta, err := tag.ReadFrom(file) if err != nil { log.Printf("File %s senza metadati ID3: %v", path, err) return nil } // relPath, _ := filepath.Rel(".", path) baseName := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)) // coverPath := filepath.Join(coversDir, baseName+".jpg") ep := Episode{ Title: meta.Title(), Artist: meta.Artist(), File: baseName + ".mp3", Cover: baseName + ".jpg", PubDate: info.ModTime().Format(time.RFC1123), Size: info.Size(), } episodes = append(episodes, ep) return nil }) return episodes, err }