Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

read.gno

9.17 Kb · 275 lines
  1package catalog
  2
  3import (
  4	"strings"
  5
  6	"gno.land/p/nym-alexiscolin000/gnoradio/store/v0"
  7	"gno.land/p/nym-alexiscolin000/gnoradio/text/v0"
  8	"gno.land/r/nym-alexiscolin000/gnoradio/data"
  9)
 10
 11// ---- Read API for the other GnoRadio realms (values only) ----
 12
 13func GenreName(g int) string {
 14	if g < 1 || g > NumGenres {
 15		return ""
 16	}
 17	return genres[g]
 18}
 19
 20func TrackCount() int    { return int(rd().count(mTracks)) }
 21func ArtistCount() int   { return int(rd().count(mArtists)) }
 22func AlbumCount() int    { return int(rd().count(mAlbums)) }
 23func PlaylistCount() int { return int(rd().count(mPlaylists)) }
 24
 25// TrackBrief is what the radio needs; playable is false for an unknown or
 26// hidden track, or one whose artist is hidden.
 27func TrackBrief(id int) (artistID, genre int, duration int64, playable_ bool) {
 28	rec := point(cTracks, id)
 29	if rec == "" {
 30		return 0, 0, 0, false
 31	}
 32	a := text.Atoi(store.Field(rec, fArtist))
 33	arec := point(cArtists, a)
 34	return a, text.Atoi(store.Field(rec, fGenre)), text.Atoi64(store.Field(rec, fDuration)),
 35		store.Field(rec, fHidden) == "" && arec != "" && store.Field(arec, aHidden) == ""
 36}
 37
 38// TrackBriefFor is TrackBrief and whether addr ("" for nobody) is the
 39// track's artist or one of its collaborators, from the same reads.
 40func TrackBriefFor(id int, addr address) (artistID, genre int, duration int64, playable_, own bool) {
 41	rec := point(cTracks, id)
 42	if rec == "" {
 43		return 0, 0, 0, false, false
 44	}
 45	a := text.Atoi(store.Field(rec, fArtist))
 46	arec := point(cArtists, a)
 47	playable_ = store.Field(rec, fHidden) == "" && arec != "" && store.Field(arec, aHidden) == ""
 48	if addr != "" && arec != "" {
 49		// splits are "addr:pct,…" and an address holds no ',' or ':'
 50		sp := store.Field(rec, fSplits)
 51		own = store.Field(arec, aOwner) == addr.String() || sp != "" && strings.Contains(","+sp, ","+addr.String()+":")
 52	}
 53	return a, text.Atoi(store.Field(rec, fGenre)), text.Atoi64(store.Field(rec, fDuration)), playable_, own
 54}
 55
 56// PlayableTitle is a track's title, "" unless it is playable (TrackBrief). An
 57// Audius or Jamendo pointer stores no title: it is "Audius track" here, the
 58// app names it from the platform.
 59func PlayableTitle(id int) string {
 60	rec := point(cTracks, id)
 61	if rec == "" || store.Field(rec, fHidden) != "" {
 62		return ""
 63	}
 64	if arec := point(cArtists, text.Atoi(store.Field(rec, fArtist))); arec == "" || store.Field(arec, aHidden) != "" {
 65		return ""
 66	}
 67	return refLabel(store.Field(rec, fOrigin), store.Field(rec, fTitle), "track")
 68}
 69
 70func TrackTitle(id int) string {
 71	if rec := point(cTracks, id); rec != "" {
 72		return refLabel(store.Field(rec, fOrigin), store.Field(rec, fTitle), "track")
 73	}
 74	return ""
 75}
 76
 77func ArtistName(artistID int) string {
 78	if rec := point(cArtists, artistID); rec != "" {
 79		return refLabel(store.Field(rec, aKind), store.Field(rec, aName), "artist")
 80	}
 81	return ""
 82}
 83
 84func ArtistOwner(artistID int) address { return address(artistAt(artistID, aOwner)) }
 85func ArtistOf(owner address) int       { return artistOf(rd(), owner) }
 86
 87// ArtistPayee is what a payment to an artist checks, from one read: who
 88// is paid, whether verified, and whether the profile is visible.
 89func ArtistPayee(id int) (owner address, verified, visible bool) {
 90	rec := point(cArtists, id)
 91	if rec == "" {
 92		return "", false, false
 93	}
 94	return address(store.Field(rec, aOwner)), store.Field(rec, aVerified) == "1", store.Field(rec, aHidden) == ""
 95}
 96func ArtistVisible(artistID int) bool {
 97	rec := point(cArtists, artistID)
 98	return rec != "" && store.Field(rec, aHidden) == ""
 99}
100
101// ---- Value getters for the home realm and tools ----
102
103// GetTrack returns a copy of a track; ok is false if unknown. A pointer's
104// empty title reads as its platform ("Audius track").
105func GetTrack(id int) (Track, bool) {
106	if tr := getTrack(rd(), id); tr != nil {
107		tr.Title = refLabel(tr.Origin, tr.Title, "track")
108		return *tr, true
109	}
110	return Track{}, false
111}
112
113func GetArtist(id int) (Artist, bool) {
114	t := rd()
115	if a := getArtist(t, id); a != nil {
116		a.Name = refLabel(a.Kind, a.Name, "artist")
117		return *withLists(t, a), true
118	}
119	return Artist{}, false
120}
121
122// ArtistByRef looks a pointer artist up by its platform id ("audius-user:12").
123func ArtistByRef(ref string) int {
124	v, _ := data.Get(cNames, strings.TrimSpace(ref))
125	return text.Atoi(v)
126}
127
128// ArtistByName looks a profile up by its (case-insensitive) name.
129func ArtistByName(name string) int {
130	v, _ := data.Get(cNames, skeleton(strings.TrimSpace(name)))
131	return text.Atoi(v)
132}
133
134func GetAlbum(id int) (Album, bool) {
135	if a := getAlbum(rd(), id); a != nil {
136		return *a, true
137	}
138	return Album{}, false
139}
140
141func GetPlaylist(id int) (Playlist, bool) {
142	if p := getPlaylist(rd(), id); p != nil {
143		return *p, true
144	}
145	return Playlist{}, false
146}
147
148// ReportCount is the number of open (unresolved) reports.
149func ReportCount() int { return int(rd().count(mOpen)) }
150
151func GetReport(id int) (ReportInfo, bool) { return getReport(rd(), id) }
152
153// UserStats returns a listener's public counters and playlists. The like
154// count reads the listener's own like ranges, one page.
155func UserStats(addr address) (likes, follows int, tipped int64, lists []int) {
156	_, likes = rangePage(cLikes, addr.String(), 0, 0)
157	u := user(rd(), addr)
158	return likes, store.Count(u.Follows), u.Tipped, u.Playlists
159}
160
161// LikedPage lists a listener's liked track ids, newest tracks first,
162// paginated. Likes are keyed by track id, so this is the newest music the
163// listener liked, not the order of their likes (that needs an index per like,
164// which would add to every like's storage deposit).
165func LikedPage(addr address, offset, limit int) []int {
166	ids, _ := rangePage(cLikes, addr.String(), max0(offset), store.Limit(limit, 100))
167	return ids
168}
169
170// ---- Narrow getters: one field without copying a whole struct ----
171
172// ArtistTrackCount is the number of tracks an artist published.
173func ArtistTrackCount(artistID int) int {
174	tl, _ := lists(rd(), artistID)
175	return store.Count(tl)
176}
177
178// ArtistTrackPage lists an artist's track ids in publishing order, paginated.
179func ArtistTrackPage(artistID, offset, limit int) []int {
180	if offset < 0 {
181		return nil
182	}
183	tl, _ := lists(rd(), artistID)
184	return store.Page(tl, offset, store.Limit(limit, 100), false)
185}
186
187// ArtistBrief returns what a link to an artist needs, without the bio or the
188// id lists; ok is false for an unknown artist.
189func ArtistBrief(artistID int) (name string, verified, hidden, ok bool) {
190	rec := point(cArtists, artistID)
191	if rec == "" {
192		return "", false, false, false
193	}
194	return refLabel(store.Field(rec, aKind), store.Field(rec, aName), "artist"), store.Field(rec, aVerified) != "", store.Field(rec, aHidden) != "", true
195}
196
197// PlaylistBrief returns a playlist's header without its track ids.
198func PlaylistBrief(id int) (owner address, title string, tracks int, hidden, ok bool) {
199	rec := rd().val(cPlaylists, store.Pad(id)) // counts the ids without decoding them
200	if id < 1 || rec == "" {
201		return "", "", 0, false, false
202	}
203	f := store.Fields(rec)
204	return address(f[0]), f[1], store.Count(f[4]), f[3] != "", true
205}
206
207// FollowsPage lists the artist ids a listener follows, paginated.
208func FollowsPage(addr address, offset, limit int) []int {
209	return store.Page(user(rd(), addr).Follows, max0(offset), store.Limit(limit, 100), false)
210}
211
212// GenrePage lists the track ids of a genre (hidden ones included), newest first.
213func GenrePage(genre, offset, limit int) []int {
214	if genre < 1 || genre > NumGenres {
215		return nil
216	}
217	ids, _ := rangePage(cGenres, store.Pad(genre), max0(offset), store.Limit(limit, 100))
218	return ids
219}
220
221// GenreCount is the number of tracks filed under a genre.
222func GenreCount(genre int) int {
223	if genre < 1 || genre > NumGenres {
224		return 0
225	}
226	return int(rd().count(mGenre + genre))
227}
228
229// TrackPage lists track ids, newest first when newest is true.
230// Ids are dense (1..count), so these pages are arithmetic.
231func TrackPage(offset, limit int, newest bool) []int {
232	return seqPage(TrackCount(), offset, limit, newest)
233}
234func ArtistPage(offset, limit int) []int   { return seqPage(ArtistCount(), offset, limit, false) }
235func AlbumPage(offset, limit int) []int    { return seqPage(AlbumCount(), offset, limit, true) }
236func PlaylistPage(offset, limit int) []int { return seqPage(PlaylistCount(), offset, limit, true) }
237
238// ReportPage lists open report ids, newest first.
239func ReportPage(offset, limit int) []int {
240	keys, _ := store.Rows(data.PageAt(cReports, max0(offset), store.Limit(limit, 100), true))
241	out := make([]int, 0, len(keys))
242	for _, k := range keys {
243		out = append(out, text.Atoi(k))
244	}
245	return out
246}
247
248func seqPage(n, offset, limit int, newest bool) []int {
249	var out []int
250	for k := max0(offset); k < n && len(out) < store.Limit(limit, 100); k++ {
251		if newest {
252			out = append(out, n-k)
253		} else {
254			out = append(out, k+1)
255		}
256	}
257	return out
258}
259
260func max0(n int) int {
261	if n < 0 {
262		return 0
263	}
264	return n
265}
266
267func TopLiked() []Rank   { return rd().top(topLiked) }
268func TopArtists() []Rank { return rd().top(topArtists) }
269func TopFans() []Rank    { return rd().top(topFans) }
270
271func Admin() address            { return adminAddr() }
272func PendingAdmin() address     { return admin.Pending() } // the address the admin role is offered to, "" if none
273func Version() string           { return version }
274func RightsTerms() string       { return rightsTerms }
275func HostAllowed(h string) bool { return data.Has(cHosts, strings.ToLower(h)) }