package playlist import ( "log" "time" "errors" "strconv" "math/rand" "encoding/json" "../archive" "../config" ) var pln = log.Println type Pop func(*Playlist) type Playlist struct { NAME string CTRACK config.Track_t CALBUM config.Album_t LIST []uint32 MAX int CALLB Pop } type PrettyPlaylist struct { NAME string CTRACK config.Track_t CALBUM config.Album_t LIST []config.Track_t MAX int } type MinimalTrack struct { ID string `json:"id"` NAME string `json:"name"` MAKER string `json:"maker"` ALBUM string `json:"album"` } type MinimalPlaylist struct { NAME string `json:"name"` CTRACK string `json:"ctrack"` CALBUM string `json:"calbum"` LIST []MinimalTrack `json:"list"` } func MakeRandom(name string, max int) (*Playlist, error) { err := archive.Build() if err != nil { return nil, err } p := &Playlist{NAME: name, MAX: max} p.LIST = make([]uint32, max) for i := 0; i < max; i++ { r, _ := Random() p.LIST[i] = r // might duplicate } return p, nil; } func (mp *MinimalPlaylist) Encode() []byte { res, err := json.Marshal(mp) if err != nil { return nil } return res } func Decode(jsonstr string) (*Playlist, error) { pp := &PrettyPlaylist{} if err := json.Unmarshal([]byte(jsonstr), pp); err != nil { return nil, err } p := pp.Unpretty() return p, nil } func (p *Playlist) Pretty() *PrettyPlaylist { pp := &PrettyPlaylist{NAME: p.NAME, CTRACK: p.CTRACK, CALBUM: p.CALBUM, MAX: p.MAX} pp.LIST = make([]config.Track_t, len(p.LIST)) for i := 0; i < len(p.LIST); i++ { pp.LIST[i] = archive.Archive_map[p.LIST[i]] } return pp } func (pp *PrettyPlaylist) Unpretty() *Playlist { p := &Playlist{NAME: pp.NAME, CTRACK: pp.CTRACK, CALBUM: pp.CALBUM, MAX: pp.MAX} p.LIST = make([]uint32, len(pp.LIST)) for i := 0; i < len(pp.LIST); i++ { p.LIST[i] = pp.LIST[i].ID } return p } func (p *Playlist) Minimal() *MinimalPlaylist { mp := &MinimalPlaylist{NAME: p.NAME, CTRACK: p.CTRACK.NAME} mp.CALBUM = p.CALBUM.MAKER + " - " + p.CALBUM.NAME mp.LIST = make([]MinimalTrack, len(p.LIST)) for i := 0; i < len(p.LIST); i++ { track := archive.Archive_map[p.LIST[i]] strid := strconv.FormatUint(uint64(track.ID), 10) mp.LIST[i] = MinimalTrack{ID: strid, NAME: track.NAME, MAKER: track.MAKER, ALBUM: track.ALBUM} } return mp } func (pp *PrettyPlaylist) Print() { pln("Name: " + pp.NAME) pln("CTRACK: " + pp.CTRACK.NAME) pln("CALBUM: " + pp.CALBUM.NAME) pln("Next:") for i, r := range pp.LIST { pln(" " + strconv.Itoa(i) + " - " + r.NAME) } } func print(slice []uint32) { for i, r := range slice { pln(" " + strconv.Itoa(i) + " - " + archive.Archive_map[r].NAME) } } // https://github.com/golang/go/wiki/SliceTricks // https://stackoverflow.com/questions/33834742/remove-and-adding-elements-to-array-in-go-lang func (p *Playlist) Pop() (string, error) { if len(p.LIST) == 0 { return "", errors.New("Playlist is empty") } t := p.LIST[0] if len(p.LIST) < 2 { p.LIST = make([]uint32, 0) } else { p.LIST = p.LIST[1:] } p.CTRACK = archive.Archive_map[t] p.CALBUM = config.Xcfg.Archive.ALBUMS[p.CTRACK.AID] if p.CALLB != nil { p.CALLB(p) } return p.CTRACK.PATH, nil } func (p *Playlist) Push(track_id uint32) error { if len(p.LIST) == p.MAX { return errors.New("Playlist is full") } p.LIST = append(p.LIST, track_id) return nil } func (p *Playlist) PushFront(track_id uint32) error { if len(p.LIST) == p.MAX { return errors.New("Playlist is full") } p.LIST = append([]uint32{ track_id }, p.LIST...) // don't forget '...'' return nil } func (p *Playlist) Insert(track_id uint32, at_index int) error { if at_index > p.MAX { return errors.New("Invalid insert index") } p.LIST = append(p.LIST, 0) copy(p.LIST[at_index+1:], p.LIST[at_index:]) p.LIST[at_index] = track_id if len(p.LIST) > p.MAX { p.LIST = p.LIST[:p.MAX] } return nil } func (p *Playlist) index(track_id uint32) int { k := -1 for i := 0; i < len(p.LIST); i++ { if p.LIST[i] == track_id { k = i } } return k } func (p *Playlist) Delete(track_id uint32) error { k := p.index(track_id); if k < 0 { return errors.New("Invalid track ID") } p.LIST = append(p.LIST[:k-1], p.LIST[k+1:]...) return nil } func (p *Playlist) Move(track_id uint32, at_index int) error { if at_index > p.MAX { return errors.New("Invalid insert index") } k := p.index(track_id); if k < 0 { return errors.New("Invalid track ID") } // pln("k: " + strconv.Itoa(k)) // pln("at_index: " + strconv.Itoa(at_index)) // pln("------") var slice_head, slice_move, slice_tail []uint32 if k < at_index { slice_head = make([]uint32, len(p.LIST[:k])) copy(slice_head, p.LIST[:k]) // slice_head = p.LIST[:k] slice_move = make([]uint32, len(p.LIST[k+1:at_index+1])) copy(slice_move, p.LIST[k+1:at_index+1]) // slice_move = p.LIST[k:at_index] slice_tail = make([]uint32, len(p.LIST[at_index+1:])) copy(slice_tail, p.LIST[at_index+1:]) p.LIST = append(slice_head, append(append(slice_move, track_id), slice_tail...)...) } else if k > at_index { slice_head = make([]uint32, len(p.LIST[:at_index])) copy(slice_head, p.LIST[:at_index]) // slice_head = p.LIST[:at_index] slice_move = make([]uint32, len(p.LIST[at_index:k])) copy(slice_move, p.LIST[at_index:k]) // slice_tail = p.LIST[k+1:] slice_tail = make([]uint32, len(p.LIST[k+1:])) copy(slice_tail, p.LIST[k+1:]) p.LIST = append(append(append(slice_head, track_id), slice_move...), slice_tail...) } // pln("slice head: ") // print(slice_head) // pln("slice move: ") // print(slice_move) // pln("** ") // pln("slice tail: ") // print(slice_tail) // pln("...........................") return nil } func Random() (uint32, string) { rand.Seed(time.Now().UTC().UnixNano()) index := archive.Archive_map_keys[rand.Intn(len(archive.Archive_map_keys) - 1)] return archive.Archive_map[index].ID, archive.Archive_map[index].NAME }