package monstersirenfetch import ( "bytes" "encoding/json" ) // SongResponse is the response of /api/song/%d. type SongResponse Response[Song] // Song holds the metadata of a song. // Fields marked with omitempty are only populated when the IsFull method returns true. type Song struct { CID StringInt `json:"cid"` Name string `json:"name"` AlbumCID StringInt `json:"albumCid"` SourceURL string `json:"sourceUrl,omitempty"` LyricURL string `json:"lyricUrl,omitempty"` MvURL string `json:"mvUrl,omitempty"` MvCoverURL string `json:"mvCoverUrl,omitempty"` Artists []string `json:"artists"` } // IsFull returns whether the metadata held by [Song] is considered full (originating from a [SongResponse]). func (s *Song) IsFull() bool { return s.SourceURL != "" } // songDirect is [Song] without its MarshalJSON method. type songDirect Song // songNullable is [Song] with corresponding nullable string fields. type songNullable struct { CID StringInt `json:"cid"` Name string `json:"name"` AlbumCID StringInt `json:"albumCid"` SourceURL string `json:"sourceUrl"` LyricURL NullableString `json:"lyricUrl"` MvURL NullableString `json:"mvUrl"` MvCoverURL NullableString `json:"mvCoverUrl"` Artists []string `json:"artists"` } func (s *Song) MarshalJSON() (data []byte, err error) { buf := new(bytes.Buffer) e := json.NewEncoder(buf) e.SetEscapeHTML(false) if !s.IsFull() { err = e.Encode((*songDirect)(s)) data = buf.Bytes() return } return json.Marshal(&songNullable{s.CID, s.Name, s.AlbumCID, s.SourceURL, NullableString(s.LyricURL), NullableString(s.MvURL), NullableString(s.MvCoverURL), s.Artists}) }