clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/tinyagent
tinyrelay / internal / records / podcasts.go
podcasts.go 3.2K
1package records23import (4 "encoding/json"5 "sort"67 "github.com/FelineStateMachine/tinyrelay/internal/event"8 "github.com/FelineStateMachine/tinyrelay/internal/podcasts"9)1011type podcastViewShow struct {12 ID string `json:"id,omitempty"`13 Pubkey string `json:"pubkey"`14 Title string `json:"title,omitempty"`15 Description string `json:"description,omitempty"`16 Image string `json:"image,omitempty"`17 Websites []string `json:"websites,omitempty"`18 Authors []podcasts.Author `json:"authors,omitempty"`19}2021type podcastViewEpisode struct {22 ID string `json:"id"`23 Pubkey string `json:"pubkey"`24 CreatedAt int64 `json:"created_at"`25 Title string `json:"title,omitempty"`26 Description string `json:"description,omitempty"`27 Image string `json:"image,omitempty"`28 Audio []podcasts.Audio `json:"audio,omitempty"`29}3031// foldPodcasts creates the compact, signed summary used by the built-in32// podcast view. The full source events remain available to Nostr clients; the33// view only carries enough information for a relay directory or RSS adapter34// to find the current shows and episodes.35func foldPodcasts(events []event.Event) ([][]string, string) {36 shows := podcasts.Shows(events)37 episodes := make([]podcasts.Episode, 0)38 for _, row := range events {39 if episode, ok := podcasts.ParseEpisode(row); ok {40 episodes = append(episodes, episode)41 }42 }43 sort.Slice(episodes, func(i, j int) bool {44 if episodes[i].CreatedAt != episodes[j].CreatedAt {45 return episodes[i].CreatedAt > episodes[j].CreatedAt46 }47 return episodes[i].ID < episodes[j].ID48 })49 if len(episodes) > 100 {50 episodes = episodes[:100]51 }52 showKeys := make([]string, 0, len(shows))53 for key := range shows {54 showKeys = append(showKeys, key)55 }56 sort.Strings(showKeys)57 if len(showKeys) > 100 {58 showKeys = showKeys[:100]59 }60 tags := make([][]string, 0, len(showKeys)+len(episodes))61 viewShows := make([]podcastViewShow, 0, len(showKeys))62 for _, key := range showKeys {63 show := shows[key]64 tags = append(tags, []string{"p", show.Pubkey, show.Title, show.Image})65 viewShows = append(viewShows, podcastViewShow{ID: show.ID, Pubkey: show.Pubkey, Title: show.Title, Description: show.Description, Image: show.Image, Websites: append([]string(nil), show.Websites...), Authors: append([]podcasts.Author(nil), show.Authors...)})66 }67 viewEpisodes := make([]podcastViewEpisode, 0, len(episodes))68 for _, episode := range episodes {69 audio := ""70 if len(episode.Audio) > 0 {71 audio = episode.Audio[0].URL72 }73 tags = append(tags, []string{"e", episode.ID, episode.Pubkey, episode.Title, audio})74 viewEpisodes = append(viewEpisodes, podcastViewEpisode{ID: episode.ID, Pubkey: episode.Pubkey, CreatedAt: episode.CreatedAt, Title: episode.Title, Description: episode.Description, Image: episode.Image, Audio: append([]podcasts.Audio(nil), episode.Audio...)})75 }76 content, _ := json.Marshal(struct {77 Shows []podcastViewShow `json:"shows"`78 Episodes []podcastViewEpisode `json:"episodes"`79 }{Shows: viewShows, Episodes: viewEpisodes})80 return tags, string(content)81}