publish.gno
4.26 Kb · 99 lines
1package radio
2
3import (
4 "strings"
5
6 "gno.land/p/nym-alexiscolin000/gnoradio/text/v0"
7 "gno.land/r/nym-alexiscolin000/gnoradio/catalog/v1"
8)
9
10// Tracks enter and change through this realm: the catalog accepts
11// PublishFor, ImportFor and EditFor from the radio writer only, so a track
12// is in the station rotations from the transaction that publishes it, paid
13// by its publisher. Nothing waits for Sync, and no robot pays for it.
14
15// PublishTrack publishes a track by the caller's own artist profile (the
16// arguments are catalog.PublishFor's) and puts it on the air in the same
17// transaction: the main station, its genre station and New this week.
18func PublishTrack(cur realm, title string, genre int, duration, license, cmo, credits, audio, audioSHA, cover, coverSHA, splits, rights string) int {
19 caller := userCaller(cur)
20 noPayment()
21 id := catalog.PublishFor(cross(cur), caller, title, genre, duration, license, cmo, credits, audio, audioSHA, cover, coverSHA, splits, rights)
22 onAir(cur, id, true)
23 return id
24}
25
26// ImportTrack adds a curated or Audius track to an unclaimed artist (the
27// arguments are catalog.ImportFor's) and puts it on the air, New this week
28// left out: an import is not a new release. The catalog admin only, from its
29// wallet or a realm that holds the role (a launch import).
30func ImportTrack(cur realm, artistID int, title string, genre int, duration, license, credits, audio, audioSHA, cover, coverSHA, sourceURL, attribution string) int {
31 noPayment()
32 id := catalog.ImportFor(cross(cur), cur.Previous().Address(), artistID, title, genre, duration, license, credits, audio, audioSHA, cover, coverSHA, sourceURL, attribution)
33 onAir(cur, id, false)
34 return id
35}
36
37// maxImportBatch bounds ImportTracks: each track costs a few M gas once the
38// realms are loaded, so a full batch stays far under the block's gas.
39const maxImportBatch = 25
40
41// ImportTracks imports up to maxImportBatch tracks in one transaction, so the
42// realms load once for the batch instead of once per track. batch holds one
43// track per line ("\n"), ImportTrack's 12 arguments separated by tabs ("\t";
44// neither can appear in a valid field). All or nothing: a bad track panics the
45// whole transaction (a malformed line is named before anything is written). It returns the id of the last track. Admin only, as
46// ImportTrack.
47func ImportTracks(cur realm, batch string) int {
48 noPayment()
49 lines := strings.Split(batch, "\n")
50 if batch == "" || len(lines) > maxImportBatch {
51 panic("radio: a batch holds 1 to " + text.Itoa(maxImportBatch) + " tracks")
52 }
53 rows := make([][]string, len(lines))
54 for i, line := range lines { // the whole batch is read before anything is written
55 f := strings.Split(line, "\t")
56 if len(f) != 12 || !text.Digits(f[0]) || !text.Digits(f[2]) {
57 panic("radio: batch line " + text.Itoa(i+1) + ": 12 tab-separated fields expected, artist and genre in digits")
58 }
59 rows[i] = f
60 }
61 by, id, t := cur.Previous().Address(), 0, rd()
62 for _, f := range rows {
63 id = catalog.ImportFor(cross(cur), by, text.MustAtoi(f[0]), f[1], text.MustAtoi(f[2]), f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10], f[11])
64 airNext(t, id, false)
65 }
66 save(cur, t)
67 return id
68}
69
70// EditTrack fixes a track's details (the arguments are catalog.EditFor's).
71// A new genre or duration is applied to the stations in the same
72// transaction, as Refresh does; other details need nothing on air.
73func EditTrack(cur realm, trackID int, title string, genre int, duration, credits, audio, audioSHA, cover, coverSHA string) {
74 caller := userCaller(cur)
75 noPayment()
76 _, oldGenre, oldDur, _ := catalog.TrackBrief(trackID)
77 catalog.EditFor(cross(cur), caller, trackID, title, genre, duration, credits, audio, audioSHA, cover, coverSHA)
78 if _, g, d, _ := catalog.TrackBrief(trackID); g != oldGenre || d != oldDur {
79 t := rd()
80 refresh(cur, t, trackID)
81 save(cur, t)
82 }
83}
84
85// onAir ingests the track the catalog just added, with Sync's own code: it
86// is the next one (Sync and every add keep the stations level with the
87// catalog), so this is one track's work whatever the catalog size.
88func onAir(cur realm, id int, isNew bool) {
89 t := rd()
90 airNext(t, id, isNew)
91 save(cur, t)
92}
93
94func airNext(t *tx, id int, isNew bool) {
95 if n := id - t.synced(); n != 1 {
96 panic("radio: the stations are behind the catalog, call Sync first")
97 }
98 ingest(t, now(), 1, isNew)
99}