// NewSong creates a track and adds to the queue
func (sc SoundCloud) NewSong(user *gumble.User, trackData *jsonq.JsonQuery, offset int, playlist Playlist) (Song, error) {
	title, _ := trackData.String("title")
	id, _ := trackData.Int("id")
	durationMS, _ := trackData.Int("duration")
	url, _ := trackData.String("permalink_url")
	thumbnail, err := trackData.String("artwork_url")
	if err != nil {
		// Song has no artwork, using profile avatar instead
		userObj, _ := trackData.Object("user")
		thumbnail, _ = jsonq.NewQuery(userObj).String("avatar_url")
	}

	song := &AudioTrack{
		id:        strconv.Itoa(id),
		title:     title,
		url:       url,
		thumbnail: thumbnail,
		submitter: user,
		duration:  durationMS / 1000,
		offset:    offset,
		format:    "mp3",
		playlist:  playlist,
		skippers:  make([]string, 0),
		dontSkip:  false,
		service:   sc,
	}
	return song, nil
}
Beispiel #2
0
// NewSong creates a track and adds to the queue
func (mc Mixcloud) NewSong(user *gumble.User, trackData *jsonq.JsonQuery, offset int) (Song, error) {
	title, _ := trackData.String("name")
	id, _ := trackData.String("slug")
	duration, _ := trackData.Int("audio_length")
	url, _ := trackData.String("url")
	thumbnail, err := trackData.String("pictures", "large")
	if err != nil {
		// Song has no artwork, using profile avatar instead
		userObj, _ := trackData.Object("user")
		thumbnail, _ = jsonq.NewQuery(userObj).String("pictures", "thumbnail")
	}

	song := &AudioTrack{
		id:        id,
		title:     title,
		url:       url,
		thumbnail: thumbnail,
		submitter: user,
		duration:  duration,
		offset:    offset,
		format:    "best",
		skippers:  make([]string, 0),
		dontSkip:  false,
		service:   mc,
	}
	return song, nil
}
Beispiel #3
0
func parse_collection(jq *jsonq.JsonQuery) *Collection {
	out := new(Collection)
	out.Count, _ = jq.Int("count")
	out.Hidden, _ = jq.Bool("hidden")
	out.Name, _ = jq.String("name")
	out.ResolveList, _ = jq.ArrayOfStrings("resolve_list")
	return out
}
Beispiel #4
0
// NewYouTubePlaylist gathers the metadata for a YouTube playlist and returns it.
func NewYouTubePlaylist(user, id string) (*YouTubePlaylist, error) {
	var apiResponse *jsonq.JsonQuery
	var err error
	// Retrieve title of playlist
	url := fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=%s&key=%s",
		id, os.Getenv("YOUTUBE_API_KEY"))
	if apiResponse, err = PerformGetRequest(url); err != nil {
		return nil, err
	}
	title, _ := apiResponse.String("items", "0", "snippet", "title")

	playlist := &YouTubePlaylist{
		id:    id,
		title: title,
	}

	// Retrieve items in playlist
	url = fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=25&playlistId=%s&key=%s",
		id, os.Getenv("YOUTUBE_API_KEY"))
	if apiResponse, err = PerformGetRequest(url); err != nil {
		return nil, err
	}
	numVideos, _ := apiResponse.Int("pageInfo", "totalResults")
	if numVideos > 25 {
		numVideos = 25
	}

	for i := 0; i < numVideos; i++ {
		index := strconv.Itoa(i)
		videoTitle, err := apiResponse.String("items", index, "snippet", "title")
		videoID, _ := apiResponse.String("items", index, "snippet", "resourceId", "videoId")
		videoThumbnail, _ := apiResponse.String("items", index, "snippet", "thumbnails", "high", "url")

		// A completely separate API call just to get the duration of a video in a
		// playlist? WHY GOOGLE, WHY?!
		var durationResponse *jsonq.JsonQuery
		url = fmt.Sprintf("https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id=%s&key=%s",
			videoID, os.Getenv("YOUTUBE_API_KEY"))
		if durationResponse, err = PerformGetRequest(url); err != nil {
			return nil, err
		}
		videoDuration, _ := durationResponse.String("items", "0", "contentDetails", "duration")

		var days, hours, minutes, seconds int64
		timestampExp := regexp.MustCompile(`P(?P<days>\d+D)?T(?P<hours>\d+H)?(?P<minutes>\d+M)?(?P<seconds>\d+S)?`)
		timestampMatch := timestampExp.FindStringSubmatch(videoDuration)
		timestampResult := make(map[string]string)
		for i, name := range timestampExp.SubexpNames() {
			if i < len(timestampMatch) {
				timestampResult[name] = timestampMatch[i]
			}
		}

		if timestampResult["days"] != "" {
			days, _ = strconv.ParseInt(strings.TrimSuffix(timestampResult["days"], "D"), 10, 32)
		}
		if timestampResult["hours"] != "" {
			hours, _ = strconv.ParseInt(strings.TrimSuffix(timestampResult["hours"], "H"), 10, 32)
		}
		if timestampResult["minutes"] != "" {
			minutes, _ = strconv.ParseInt(strings.TrimSuffix(timestampResult["minutes"], "M"), 10, 32)
		}
		if timestampResult["seconds"] != "" {
			seconds, _ = strconv.ParseInt(strings.TrimSuffix(timestampResult["seconds"], "S"), 10, 32)
		}

		totalSeconds := int((days * 86400) + (hours * 3600) + (minutes * 60) + seconds)
		var durationString string
		if hours != 0 {
			if days != 0 {
				durationString = fmt.Sprintf("%d:%02d:%02d:%02d", days, hours, minutes, seconds)
			} else {
				durationString = fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds)
			}
		} else {
			durationString = fmt.Sprintf("%d:%02d", minutes, seconds)
		}

		if dj.conf.General.MaxSongDuration == 0 || totalSeconds <= dj.conf.General.MaxSongDuration {
			playlistSong := &YouTubeSong{
				submitter: user,
				title:     videoTitle,
				id:        videoID,
				filename:  videoID + ".m4a",
				duration:  durationString,
				thumbnail: videoThumbnail,
				skippers:  make([]string, 0),
				playlist:  playlist,
				dontSkip:  false,
			}
			dj.queue.AddSong(playlistSong)
		}
	}
	return playlist, nil
}