Beispiel #1
0
//Adds youtube clip to be played
func Add(user *gumble.User, url string) {
	if url == "" {
		jew.SendPM(user, "There needs to be a link silly.")
	} else {

		//Accepted patterns for youtube links
		youtubePatterns := []string{
			`https?:\/\/www\.youtube\.com\/watch\?v=([\w-]+)(\&t=\d*m?\d*s?)?`,
			`https?:\/\/youtube\.com\/watch\?v=([\w-]+)(\&t=\d*m?\d*s?)?`,
			`https?:\/\/youtu.be\/([\w-]+)(\?t=\d*m?\d*s?)?`,
			`https?:\/\/youtube.com\/v\/([\w-]+)(\?t=\d*m?\d*s?)?`,
			`https?:\/\/www.youtube.com\/v\/([\w-]+)(\?t=\d*m?\d*s?)?`,
		}
		matchFound := false
		shortURL := ""
		startOffset := ""

		//Checks if url fits accepted patterns
		for _, pattern := range youtubePatterns {
			if re, err := regexp.Compile(pattern); err == nil {
				if re.MatchString(url) {
					matchFound = true
					matches := re.FindAllStringSubmatch(url, -1)
					shortURL = matches[0][1]
					if len(matches[0]) == 3 {
						startOffset = matches[0][2]
					}
					break
				}
			}
		}

		//If url is accepted, send out JsonQuery to fetch title from google youtuble API
		if matchFound {
			var apiResponse *jsonq.JsonQuery
			var err error
			APIurl := fmt.Sprintf("https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=%s&key=%s",
				shortURL, os.Getenv("YOUTUBE_API_KEY"))
			if apiResponse, err = PerformGetRequest(APIurl); err != nil {
				panic(err)
			}
			title, _ := apiResponse.String("items", "0", "snippet", "title")

			//Print title and play clip
			jew.client.Self.Channel.Send(fmt.Sprintf("<a href=\"%s\">%s</a> added by %s", url, title, user.Name), false)
			if !jew.audioStream.IsPlaying() {
				if err := DownloadYoutube(shortURL); err == nil {
					PlayYoutube(startOffset, shortURL)
				} else {
					jew.SendPM(user, "Error downloading")
				}
			}
		} else {
			jew.SendPM(user, "Url not parsable")
		}
	}
}
Beispiel #2
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 #3
0
// NewPlaylist gathers the metadata for a YouTube playlist and returns it.
func (yt YouTube) NewPlaylist(user *gumble.User, id string) ([]Song, error) {
	var apiResponse *jsonq.JsonQuery
	var songArray []Song
	var err error
	// Retrieve title of playlist
	url := fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=%s&key=%s", id, dj.conf.ServiceKeys.Youtube)
	if apiResponse, err = PerformGetRequest(url); err != nil {
		return nil, err
	}
	title, _ := apiResponse.String("items", "0", "snippet", "title")

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

	maxSongs := math.MaxInt32
	if dj.conf.General.MaxSongPerPlaylist > 0 {
		maxSongs = dj.conf.General.MaxSongPerPlaylist
	}
	pageToken := ""
	for len(songArray) < maxSongs { //Iterate over the pages

		// Retrieve items in this page of the playlist
		url = fmt.Sprintf("https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=%s&key=%s&pageToken=%s",
			id, dj.conf.ServiceKeys.Youtube, pageToken)
		if apiResponse, err = PerformGetRequest(url); err != nil {
			return nil, err
		}

		songs, _ := apiResponse.Array("items")
		for j := 0; j < len(songs) && len(songArray) < maxSongs; j++ {
			index := strconv.Itoa(j)
			videoID, _ := apiResponse.String("items", index, "snippet", "resourceId", "videoId")
			if song, err := yt.NewSong(user, videoID, "", playlist); err == nil {
				songArray = append(songArray, song)
			}
		}
		if pageToken, err = apiResponse.String("nextPageToken"); err != nil {
			break
		}
	}
	return songArray, nil
}
Beispiel #4
0
func getStorageFromConfig(key string, jq *jsonq.JsonQuery) (gostorages.Storage, error) {
	storageType, err := jq.String("storage", key, "type")

	parameter, ok := Storages[storageType]

	if !ok {
		return nil, fmt.Errorf("Storage %s does not exist", key)
	}

	config, err := jq.Object("storage", key)

	if err != nil {
		return nil, err
	}

	storage, err := parameter(util.MapInterfaceToMapString(config))

	if err != nil {
		return nil, err
	}

	return storage, err
}
// NewRequest creates the requested song/playlist and adds to the queue
func (sc SoundCloud) NewRequest(user *gumble.User, url string) ([]Song, error) {
	var apiResponse *jsonq.JsonQuery
	var songArray []Song
	var err error
	timesplit := strings.Split(url, "#t=")
	url = fmt.Sprintf("http://api.soundcloud.com/resolve?url=%s&client_id=%s", timesplit[0], dj.conf.ServiceKeys.SoundCloud)
	if apiResponse, err = PerformGetRequest(url); err != nil {
		return nil, errors.New(fmt.Sprintf(INVALID_API_KEY, sc.ServiceName()))
	}

	tracks, err := apiResponse.ArrayOfObjects("tracks")
	if err == nil {
		// PLAYLIST
		// Create playlist
		title, _ := apiResponse.String("title")
		permalink, _ := apiResponse.String("permalink_url")
		playlist := &AudioPlaylist{
			id:    permalink,
			title: title,
		}

		if dj.conf.General.MaxSongPerPlaylist > 0 && len(tracks) > dj.conf.General.MaxSongPerPlaylist {
			tracks = tracks[:dj.conf.General.MaxSongPerPlaylist]
		}
		// Add all tracks
		for _, t := range tracks {
			if song, err := sc.NewSong(user, jsonq.NewQuery(t), 0, playlist); err == nil {
				songArray = append(songArray, song)
			}
		}
		return songArray, nil
	} else {
		// SONG
		// Calculate offset
		offset := 0
		if len(timesplit) == 2 {
			timesplit = strings.Split(timesplit[1], ":")
			multiplier := 1
			for i := len(timesplit) - 1; i >= 0; i-- {
				time, _ := strconv.Atoi(timesplit[i])
				offset += time * multiplier
				multiplier *= 60
			}
		}

		// Add the track
		if song, err := sc.NewSong(user, apiResponse, offset, nil); err == nil {
			return append(songArray, song), err
		}
		return nil, err
	}
}
Beispiel #6
0
// NewYouTubeSong gathers the metadata for a song extracted from a YouTube video, and returns
// the song.
func NewYouTubeSong(user, id, offset string, playlist *YouTubePlaylist) (*YouTubeSong, error) {
	var apiResponse *jsonq.JsonQuery
	var err error
	url := fmt.Sprintf("https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=%s&key=%s",
		id, os.Getenv("YOUTUBE_API_KEY"))
	if apiResponse, err = PerformGetRequest(url); err != nil {
		return nil, err
	}

	var offsetDays, offsetHours, offsetMinutes, offsetSeconds int64
	if offset != "" {
		offsetExp := regexp.MustCompile(`t\=(?P<days>\d+d)?(?P<hours>\d+h)?(?P<minutes>\d+m)?(?P<seconds>\d+s)?`)
		offsetMatch := offsetExp.FindStringSubmatch(offset)
		offsetResult := make(map[string]string)
		for i, name := range offsetExp.SubexpNames() {
			if i < len(offsetMatch) {
				offsetResult[name] = offsetMatch[i]
			}
		}

		if offsetResult["days"] != "" {
			offsetDays, _ = strconv.ParseInt(strings.TrimSuffix(offsetResult["days"], "d"), 10, 32)
		}
		if offsetResult["hours"] != "" {
			offsetHours, _ = strconv.ParseInt(strings.TrimSuffix(offsetResult["hours"], "h"), 10, 32)
		}
		if offsetResult["minutes"] != "" {
			offsetMinutes, _ = strconv.ParseInt(strings.TrimSuffix(offsetResult["minutes"], "m"), 10, 32)
		}
		if offsetResult["seconds"] != "" {
			offsetSeconds, _ = strconv.ParseInt(strings.TrimSuffix(offsetResult["seconds"], "s"), 10, 32)
		}
	}

	title, _ := apiResponse.String("items", "0", "snippet", "title")
	thumbnail, _ := apiResponse.String("items", "0", "snippet", "thumbnails", "high", "url")
	duration, _ := apiResponse.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(duration)
	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 {
		song := &YouTubeSong{
			submitter: user,
			title:     title,
			id:        id,
			offset:    int((offsetDays * 86400) + (offsetHours * 3600) + (offsetMinutes * 60) + offsetSeconds),
			filename:  id + ".m4a",
			duration:  durationString,
			thumbnail: thumbnail,
			skippers:  make([]string, 0),
			playlist:  nil,
			dontSkip:  false,
		}
		dj.queue.AddSong(song)
		return song, nil
	}
	return nil, errors.New("Song exceeds the maximum allowed duration.")
}
Beispiel #7
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
}
// 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 #9
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
}
func getString(j *jsonq.JsonQuery, s ...string) string {
	v, _ := j.String(s...)
	return v
}