<commit_before>/*
 * MumbleDJ
 * By <NAME>
 * playlist.go
 * Copyright (c) 2014, 2015 <NAME> (MIT License)
 */

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/jmoiron/jsonq"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

// Playlist type declaration.
type Playlist struct {
	id    string
	title string
}

// Returns a new Playlist type. Before returning the new type, the playlist's metadata is collected
// via the YouTube Gdata API.
func NewPlaylist(user, id string) (*Playlist, error) {
	jsonUrl := fmt.Sprintf("http://gdata.youtube.com/feeds/api/playlists/%s?v=2&alt=jsonc&maxresults=25", id)
	jsonString := ""

	if response, err := http.Get(jsonUrl); err == nil {
		defer response.Body.Close()
		if response.StatusCode != 400 && response.StatusCode != 404 {
			if body, err := ioutil.ReadAll(response.Body); err == nil {
				jsonString = string(body)
			}
		} else {
			return nil, errors.New("Invalid YouTube ID supplied.")
		}
	} else {
		return nil, errors.New("An error occurred while receiving HTTP GET request.")
	}

	jsonData := map[string]interface{}{}
	decoder := json.NewDecoder(strings.NewReader(jsonString))
	decoder.Decode(&jsonData)
	jq := jsonq.NewQuery(jsonData)

	playlistTitle, _ := jq.String("data", "title")
	playlistItems, _ := jq.Int("data", "totalItems")
	if playlistItems > 25 {
		playlistItems = 25
	}

	playlist := &Playlist{
		id:    id,
		title: playlistTitle,
	}

	for i := 0; i < playlistItems; i++ {
		index := strconv.Itoa(i)
		songTitle, _ := jq.String("data", "items", index, "video", "title")
		songId, _ := jq.String("data", "items", index, "video", "id")
		songThumbnail, _ := jq.String("data", "items", index, "video", "thumbnail", "hqDefault")
		duration, _ := jq.Int("data", "items", index, "video", "duration")
		songDuration := fmt.Sprintf("%d:%02d", duration/60, duration%60)
		newSong := &Song{
			submitter:    user,
			title:        songTitle,
			youtubeId:    songId,
			duration:     songDuration,
			thumbnailUrl: songThumbnail,
			playlist:     playlist,
			dontSkip:     false,
		}
		// Don't spam the chat if a playlist contains songs that are too long
		if dj.conf.General.MaxSongDuration == 0 || duration <= dj.conf.General.MaxSongDuration {
			dj.queue.AddSong(newSong)
		}
	}

	return playlist, nil
}

// Adds a skip to the skippers slice for the current playlist.
func (p *Playlist) AddSkip(username string) error {
	for _, user := range dj.playlistSkips[p.id] {
		if username == user {
			return errors.New("This user has already skipped the current song.")
		}
	}
	dj.playlistSkips[p.id] = append(dj.playlistSkips[p.id], username)
	return nil
}
<commit_msg>Fixed panic when a song exceeded allowed duration<commit_after>/*
 * MumbleDJ
 * By <NAME>
 * playlist.go
 * Copyright (c) 2014, 2015 <NAME> (MIT License)
 */

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/jmoiron/jsonq"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

// Playlist type declaration.
type Playlist struct {
	id    string
	title string
}

// Returns a new Playlist type. Before returning the new type, the playlist's metadata is collected
// via the YouTube Gdata API.
func NewPlaylist(user, id string) (*Playlist, error) {
	jsonUrl := fmt.Sprintf("http://gdata.youtube.com/feeds/api/playlists/%s?v=2&alt=jsonc&maxresults=25", id)
	jsonString := ""

	if response, err := http.Get(jsonUrl); err == nil {
		defer response.Body.Close()
		if response.StatusCode != 400 && response.StatusCode != 404 {
			if body, err := ioutil.ReadAll(response.Body); err == nil {
				jsonString = string(body)
			}
		} else {
			return nil, errors.New("Invalid YouTube ID supplied.")
		}
	} else {
		return nil, errors.New("An error occurred while receiving HTTP GET request.")
	}

	jsonData := map[string]interface{}{}
	decoder := json.NewDecoder(strings.NewReader(jsonString))
	decoder.Decode(&jsonData)
	jq := jsonq.NewQuery(jsonData)

	playlistTitle, _ := jq.String("data", "title")
	playlistItems, _ := jq.Int("data", "totalItems")
	if playlistItems > 25 {
		playlistItems = 25
	}

	playlist := &Playlist{
		id:    id,
		title: playlistTitle,
	}
	j := 0
	for i := 0; i < playlistItems; i++ {
		index := strconv.Itoa(j)
		songTitle, _ := jq.String("data", "items", index, "video", "title")
		songId, _ := jq.String("data", "items", index, "video", "id")
		songThumbnail, _ := jq.String("data", "items", index, "video", "thumbnail", "hqDefault")
		duration, _ := jq.Int("data", "items", index, "video", "duration")
		songDuration := fmt.Sprintf("%d:%02d", duration/60, duration%60)
		newSong := &Song{
			submitter:    user,
			title:        songTitle,
			youtubeId:    songId,
			duration:     songDuration,
			thumbnailUrl: songThumbnail,
			playlist:     playlist,
			dontSkip:     false,
		}
		// Don't spam the chat if a playlist contains songs that are too long
		if dj.conf.General.MaxSongDuration == 0 || duration <= dj.conf.General.MaxSongDuration {
			dj.queue.AddSong(newSong)
			j += 1
		} 
	}

	return playlist, nil
}

// Adds a skip to the skippers slice for the current playlist.
func (p *Playlist) AddSkip(username string) error {
	for _, user := range dj.playlistSkips[p.id] {
		if username == user {
			return errors.New("This user has already skipped the current song.")
		}
	}
	dj.playlistSkips[p.id] = append(dj.playlistSkips[p.id], username)
	return nil
}

{'fraction_non_alphanumeric': 0.14958863126402394, 'fraction_numerical': 0.011219147344801795, 'mean_word_length': 3.758896797153025, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '558868', 'n_tokens_mistral': 2059, 'n_tokens_neox': 1859, 'n_words': 489}