- package main
- import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/http"
- "os"
- "os/exec"
- "strconv"
- )
- const (
- token string = "xxxxxxxxxxxxxxxxxxxxxxxxx" //please use your own flvxz token
- downloadPath = "/home/justin/Videos/" //change to your own download path
- )
- type FlvxzJSON struct {
- Title string `json:"title"`
- Files []struct {
- Furl string `json:"furl"`
- Ftype string `json:"ftype"`
- Bytes int `json:"bytes"`
- Seconds int `json:"seconds"`
- Time string `json:"time"`
- Size string `json:"size"`
- } `json:"files"`
- Site string `json:"site"`
- Quality string `json:"quality"`
- Hd int `json:"hd"`
- }
- func checkError(err error) {
- if err != nil {
- panic(err)
- }
- }
- //parse
- func flvxz(url string) (string, string, []string) {
- url = base64.URLEncoding.EncodeToString([]byte(url))
- api := "http://api.flvxz.com/token/" + token + "/url/" + url + "/hd/9/jsonp/purejson/ftype/flv.mp4"
- resp, errGet := http.Get(api)
- defer resp.Body.Close()
- checkError(errGet)
- videoJSON, errReadAll := ioutil.ReadAll(resp.Body)
- checkError(errReadAll)
- var res [1]FlvxzJSON
- errUnmarshal := json.Unmarshal(videoJSON, &res)
- checkError(errUnmarshal)
- count := len(res[0].Files)
- if count == 0 {
- panic("Cannot parse !\\nplease chack the URL\\n")
- }
- title := res[0].Title
- ftype := "." + res[0].Files[0].Ftype
- videoFiles := make([]string, count)
- for i := 0; i < count; i++ {
- videoFiles[i] = res[0].Files[i].Furl
- }
- return title, ftype, videoFiles
- }
- func createM3u(title string, ftpye string, count int) {
- m3u := "#EXTM3U"
- for i := 0; i < count; i++ {
- m3u += "\\n#EXTINF:" + title + "\\n" + title + "_" + strconv.Itoa(i+1) + ftpye
- }
- ioutil.WriteFile(downloadPath+title+".m3u", []byte(m3u), 0644)
- }
- func redirect(url string) string {
- resp, err := http.Head(url)
- defer resp.Body.Close()
- checkError(err)
- url = resp.Request.URL.String()
- return url
- }
- func download(i int, title string, ftpye string, videoFiles []string, execChans chan bool, doneChans chan bool) {
- execChans <- true // 放在函数的开始处,用来阻塞执行,如果通道里的数量超过设定数量,在没有读取完成前,不会运行
- isOk := false
- fmt.Printf("NO: %d start...\\n", i+1)
- argv1 := "--user-agent=\\"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060728 Firefox/1.5\\""
- argv2 := downloadPath + title + "_" + strconv.Itoa(i+1) + ftpye
- argv3 := videoFiles[i]
- defer func() {
- doneChans <- isOk
- }()
- cmd := exec.Command("wget", argv1, "-O", argv2, argv3)
- _, execErr := cmd.Output()
- checkError(execErr)
- isOk = true
- return
- }
- func main() {
- var url string
- if len(os.Args) > 1 {
- url = os.Args[1]
- } else {
- fmt.Println("Please input the URL :")
- fmt.Scanln(&url)
- }
- title, ftpye, videoFiles := flvxz(url)
- fmt.Printf("downloading %s now\\n", title)
- count := len(videoFiles)
- createM3u(title, ftpye, count)
- for i := 0; i < count; i++ {
- videoFiles[i] = redirect(videoFiles[i]) //get the real URL
- }
- pnum := 5 // channel amount
- if pnum > count {
- pnum = count
- }
- execChans := make(chan bool, pnum)
- doneChans := make(chan bool, 1)
- for i := 0; i < count; i++ {
- go download(i, title, ftpye, videoFiles, execChans, doneChans)
- }
- for i := 0; i < count; i++ {
- msg := <-doneChans // 完成一个,同时获取下一个任务
- <-execChans // 紧接着读取下一个任务,类是于beanstalkd的任务分发机制
- if msg { // 获取失败时,打印该网址失败。
- fmt.Printf("No. %d/%d is succeed\\n", i+1, count)
- } else {
- fmt.Printf("No. %d/%d is failure\\n", i+1, count)
- }
- }
- close(doneChans) // 关闭完成信号
- close(execChans) // 关闭执行信号
- fmt.Println("done!")
- }
- //该片段来自于http://www.codesnippet.cn/detail/0112201411117.html
来源: http://www.codesnippet.cn/detail/0112201411117.html