Пример #1
0
func (d Downloader) getStream() (stream Stream, err error) {
	tok, err := api.API.Token(api.TokenLive, d.channel)
	if err != nil {
		return
	}
	u := api.Usher.Channel(d.channel, tok.Values())
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return
	}
	res, err := d.httpClient.Do(req)
	if err != nil {
		return
	}
	p, _, err := m3u8.DecodeFrom(res.Body, true)
	if err != nil {
		return stream, ErrStreamOffline
	}
	switch p := p.(type) {
	case *m3u8.MasterPlaylist:
		{
			for _, variant := range p.Variants {
				if variant.Video != targetVideo {
					continue
				}
				stream.URL = variant.URI
				return stream, nil
			}
		}
	}
	return stream, ErrTargetVideoNotFound
}
Пример #2
0
func (d Downloader) DownloadChunks(stream Stream) error {
	log.Println("downloading chunks")
	req, err := http.NewRequest("GET", stream.URL, nil)
	if err != nil {
		return err
	}
	res, err := d.httpClient.Do(req)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	p, _, err := m3u8.DecodeFrom(res.Body, true)
	if err != nil {
		return err
	}
	playlistURL, err := url.Parse(stream.URL)
	if err != nil {
		return err
	}
	var (
		chunkURL string
	)
	switch p := p.(type) {
	case *m3u8.MediaPlaylist:
		{
			for _, segment := range p.Segments {
				if segment == nil {
					continue
				}
				chunkURL = segment.URI
				if !strings.HasPrefix(chunkURL, "http") {
					u, err := playlistURL.Parse(segment.URI)
					if err != nil {
						log.Println("parse", err)
						continue
					}
					chunkURL = u.String()
				}
				_, hit := d.cache.Get(chunkURL)
				if hit {
					continue
				}
				if err := d.DownloadChunk(chunkURL); err != nil {
					d.notify("chunk download error", err)
				} else {
					d.cache.Add(chunkURL, nil)
				}
			}
		}
	default:
		return errors.New("Bad playlist type")
	}
	return nil
}
Пример #3
0
func main() {
	GOPATH := os.Getenv("GOPATH")
	if GOPATH == "" {
		panic("$GOPATH is empty")
	}
	m3u8File := "github.com/grafov/m3u8/sample-playlists/media-playlist-with-byterange.m3u8"
	f, err := os.Open(path.Join(GOPATH, "src", m3u8File))
	if err != nil {
		panic(err)
	}
	p, listType, err := m3u8.DecodeFrom(bufio.NewReader(f), true)
	if err != nil {
		panic(err)
	}
	switch listType {
	case m3u8.MEDIA:
		mediapl := p.(*m3u8.MediaPlaylist)
		fmt.Printf("%+v\n", mediapl)
	case m3u8.MASTER:
		masterpl := p.(*m3u8.MasterPlaylist)
		fmt.Printf("%+v\n", masterpl)
	}
}
Пример #4
0
func Get(channelname string) (int, string) {
	cli := http.DefaultClient

	accessTokenurl := "http://api.twitch.tv/api/channels/" + channelname + "/access_token"
	req, err := http.NewRequest("GET", accessTokenurl, nil)
	if err != nil {
		fmt.Println(err)
	}

	req.Header.Set("User-Agent", "letr.it/twitchaudio 1.0")

	resp, err := cli.Do(req)
	if err != nil {
		fmt.Println("Looks like something went wrong with the request:\n", err)
	}
	defer resp.Body.Close()

	var accesstoken Accesstoken
	tempbody, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal(tempbody, &accesstoken)
	if err != nil {
		fmt.Println("Something went wrong with the JSON:\n", err)
	}

	m3u8url := "http://usher.twitch.tv/api/channel/hls/" + channelname + ".m3u8?sig=" + accesstoken.Sig + "&token=" + accesstoken.Token + "&allow_source=true&allow_audio_only=true"
	req, err = http.NewRequest("GET", m3u8url, nil)
	if err != nil {
		fmt.Println(err)
	}

	req.Header.Set("User-Agent", "letr.it/twitchaudio 1.0")

	resp, err = cli.Do(req)
	if err != nil {
		fmt.Println("Looks like something went wrong with the request:\n", err)
	}
	defer resp.Body.Close()

	//tempbody, err = ioutil.ReadAll(resp.Body)

	//allstreamsraw := string(tempbody)

	p, listType, err := m3u8.DecodeFrom(bufio.NewReader(resp.Body), true)
	if err != nil {
		//panic(err)
		return 0, "no go"
	}
	switch listType {
	case m3u8.MEDIA:
		mediapl := p.(*m3u8.MediaPlaylist)
		fmt.Printf("%+v\n", mediapl)
	case m3u8.MASTER:
		masterpl := p.(*m3u8.MasterPlaylist)
		//fmt.Printf("%+v\n", masterpl.Variants[5])
		for _, data := range masterpl.Variants {
			if data.Video == "audio_only" {
				return 1, data.URI
			}

		}
	}
	return 0, "no go"
}
Пример #5
0
func getPlaylist(urlStr string, recTime time.Duration, useLocalTime bool, dlc chan *Download) {
	startTime := time.Now()
	var recDuration time.Duration = 0
	cache := lru.New(64)
	playlistUrl, err := url.Parse(urlStr)
	if err != nil {
		log.Fatal(err)
	}
	for {
		req, err := http.NewRequest("GET", urlStr, nil)
		if err != nil {
			log.Fatal(err)
		}
		resp, err := doRequest(client, req)
		if err != nil {
			log.Print(err)
			time.Sleep(time.Duration(3) * time.Second)
		}
		playlist, listType, err := m3u8.DecodeFrom(resp.Body, true)
		if err != nil {
			log.Fatal(err)
		}
		resp.Body.Close()
		if listType == m3u8.MEDIA {
			mpl := playlist.(*m3u8.MediaPlaylist)
			for _, v := range mpl.Segments {
				if v != nil {
					var msURI string
					if strings.HasPrefix(v.URI, "http") {
						msURI, err = url.QueryUnescape(v.URI)
						if err != nil {
							log.Fatal(err)
						}
					} else {
						msUrl, err := playlistUrl.Parse(v.URI)
						if err != nil {
							log.Print(err)
							continue
						}
						msURI, err = url.QueryUnescape(msUrl.String())
						if err != nil {
							log.Fatal(err)
						}
					}
					_, hit := cache.Get(msURI)
					if !hit {
						cache.Add(msURI, nil)
						if useLocalTime {
							recDuration = time.Now().Sub(startTime)
						} else {
							recDuration += time.Duration(int64(v.Duration * 1000000000))
						}
						dlc <- &Download{msURI, recDuration}
					}
					if recDuration != 0 && recDuration >= recTime {
						close(dlc)
						return
					}
				}
			}
			if mpl.Closed {
				close(dlc)
				return
			} else {
				time.Sleep(time.Duration(int64(mpl.TargetDuration * 1000000000)))
			}
		} else {
			log.Fatal("Not a valid media playlist")
		}
	}
}