package main import ( "bytes" "context" "crypto/rand" "encoding/binary" "encoding/json" "errors" "io" "log" "math/big" "time" mrand "math/rand" "github.com/faiface/beep" "github.com/sosodev/duration" "google.golang.org/api/option" "google.golang.org/api/youtube/v3" ) var ( yt_url = "https://www.youtube.com/watch?v=%s" ) func init() { log.Println("youtube.go loading..") var err error apikey := config.GetString("youtube.apikey") app.youtube, err = youtube.NewService(context.Background(), option.WithAPIKey(apikey)) if err != nil { log.Fatal(err) } log.Println("youtube.go done.") } type YT struct { dst io.WriteCloser pcm io.ReadCloser dur time.Duration pos time.Duration f beep.Format } func ShufflePlaylist(list []string) ([]string, error) { seedb := make([]byte, 32) _, err := rand.Read(seedb) if err != nil { return nil, err } seed := binary.BigEndian.Uint64(seedb) mrand.Seed(int64(seed)) mrand.Shuffle(len(list), func(i, j int) { list[i], list[j] = list[j], list[i] }) return list, nil } func (app *App) GetSong(list []string) string { return list[app.plidx] } func (app *App) GetNextSong(list []string) string { app.plidx++ if app.plidx >= len(app.active) { app.plidx = 0 } return list[app.plidx] } func (app *App) GetPrevSong(list []string) string { app.plidx-- if app.plidx < 0 { app.plidx = len(list) } return list[app.plidx] } func GetRandomSong(list []string) string { if !(len(list) > 0) { return "" } idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(list)-1))) if err != nil { log.Println("Failed to get random int, ", err) return "" } return list[idx.Int64()] } type VideoInfo struct { Title string Channel string Len time.Duration Uri string } func (app App) Video(vid string) (out VideoInfo, err error) { _, r, err := app.cache.GetOrCreate(vid+".videoinfo", func() (io.ReadCloser, error) { call := app.youtube.Videos.List([]string{"snippet", "contentDetails"}) call.MaxResults(1) call.Id(vid) resp, err := call.Do() if err != nil { return nil, err } if len(resp.Items) != 1 { return nil, errors.New("Response contains not 1 item!") } video := resp.Items[0] songdur, err := duration.Parse(video.ContentDetails.Duration) if err != nil { return nil, err } out := new(VideoInfo) out.Len = songdur.ToTimeDuration() out.Title = video.Snippet.Title out.Channel = video.Snippet.ChannelTitle out.Uri = vid var buf bytes.Buffer json.NewEncoder(&buf).Encode(out) return io.NopCloser(&buf), nil }) if err != nil { return } json.NewDecoder(r).Decode(&out) return out, nil } func (app App) Playlist(playlist string) ([]string, error) { call := app.youtube.PlaylistItems.List([]string{"contentDetails"}) pageToken := "" call = call.MaxResults(50) call = call.PlaylistId(playlist) if pageToken != "" { call = call.PageToken(pageToken) } var list []string for { response, err := call.Do() if err != nil { return nil, err } for _, item := range response.Items { list = append(list, item.ContentDetails.VideoId) } pageToken = response.NextPageToken if pageToken == "" { break } } return list, nil //return fmt.Sprintf(yt_url, list[rand.Intn(len(list))]) }