2022-11-18 21:18:12 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-11-19 16:37:49 +00:00
|
|
|
"bytes"
|
2022-11-18 21:18:12 +00:00
|
|
|
"context"
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/binary"
|
2022-11-19 16:37:49 +00:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2022-11-18 21:18:12 +00:00
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"math/big"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
mrand "math/rand"
|
|
|
|
|
|
|
|
"github.com/faiface/beep"
|
2022-11-19 16:37:49 +00:00
|
|
|
"github.com/sosodev/duration"
|
2022-11-18 21:18:12 +00:00
|
|
|
"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 {
|
2022-11-19 16:37:49 +00:00
|
|
|
return list[app.plidx]
|
2022-11-18 21:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (app *App) GetNextSong(list []string) string {
|
|
|
|
app.plidx++
|
|
|
|
if app.plidx >= len(app.active) {
|
|
|
|
app.plidx = 0
|
|
|
|
}
|
2022-11-19 16:37:49 +00:00
|
|
|
return list[app.plidx]
|
2022-11-18 21:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (app *App) GetPrevSong(list []string) string {
|
|
|
|
app.plidx--
|
|
|
|
if app.plidx < 0 {
|
|
|
|
app.plidx = len(list)
|
|
|
|
}
|
2022-11-19 16:37:49 +00:00
|
|
|
return list[app.plidx]
|
2022-11-18 21:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 ""
|
|
|
|
}
|
2022-11-19 16:37:49 +00:00
|
|
|
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
|
2022-11-18 21:18:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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))])
|
|
|
|
}
|