Skip to content
This repository has been archived by the owner on Nov 21, 2022. It is now read-only.

Commit

Permalink
api: Fixes to download API.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nyah Check committed Sep 26, 2017
1 parent 55186f6 commit c807884
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 75 deletions.
78 changes: 39 additions & 39 deletions api/apiconv.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,72 +12,72 @@ import (
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"

"github.com/Sirupsen/logrus"
)

//Converts Decoded Video file to mp3 by default with 123 bitrate or to
//flv if otherwise specified and downloads to system
func APIConvertVideo(file, id, format string, bitrate uint, decVideo []string) error {
func ApiConvertVideo(file, id, format string, bitrate uint, decVideo []string) error {
cmd := exec.Command("ffmpeg", "-i", "-", "-ab", fmt.Sprintf("%dk", bitrate), file)
stdin, err := cmd.StdinPipe()
err = os.MkdirAll(filepath.Dir(file), 666)
if err != nil {
return err
}
if filepath.Ext(file) != ".mp3" && filepath.Ext(file) != ".flv" {
file = file[:len(file)-4] + ".mp3"
out, err := os.Create(file)
if err != nil {
return err
}

//logrus.Infof("Converting video to %q format", filepath.Ext(file))
if filepath.Ext(file) == ".mp3" {
/* NOTE: To modify to use Go ffmpeg bindings or cgo */

buf := &bytes.Buffer{}
gob.NewEncoder(buf).Encode(decVideo)
_, err = exec.LookPath("ffmpeg")
if err != nil {
return errors.New("ffmpeg not found on system")
}

cmd.Start()
//logrus.Infof("Downloading mp3 file to disk %s", file)
stdin.Write(buf.Bytes()) //download file.

} else {
out, err := os.Create(file)
if err != nil {
logrus.Errorf("Unable to download video file: %v", err)
return err
}
err = apiDownloadVideo(id, out)
stdin, err := cmd.StdinPipe()
if err != nil {
return err
}

buf := &bytes.Buffer{}
gob.NewEncoder(buf).Encode(decVideo)
_, err = exec.LookPath("ffmpeg")
if err != nil {
return errors.New("ffmpeg not found on system")
}

cmd.Start()
//logrus.Infof("Downloading mp3 file to disk %s", file)
stdin.Write(buf.Bytes()) //download file.

return nil
}

//Downloads decoded video stream.
func apiDownloadVideo(url string, out io.Writer) error {
//logrus.Infof("Downloading file stream")

resp, err := http.Get(videoExtractor + url)
func ApiDownloadVideo(file string, url string, video *RawVideoData) error {
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("requesting stream: %s", err)
log.Printf("Http.Get\nerror: %s\nURL: %s\n", err, url)
return err
}
defer resp.Body.Close()
video.Vlength = float64(resp.ContentLength)

if resp.StatusCode != 200 {
return fmt.Errorf("reading answer: non 200 status code received: '%s'", err)
log.Printf("Reading Output: status code : '%v'", resp.StatusCode, err)
return errors.New("non 200 status code received")
}
length, err := io.Copy(out, resp.Body)
err = os.MkdirAll(filepath.Dir(file), 666)
if err != nil {
return fmt.Errorf("saving file: %s (%d bytes copied)", err, length)
return err
}
out, err := os.Create(file)
if err != nil {
return err
}
mw := io.MultiWriter(out, video)
_, err = io.Copy(mw, resp.Body)
if err != nil {
log.Println("Download Error: ", err)
return err
}

//logrus.Infof("Downloaded %d bytes", length)

return nil
}
106 changes: 71 additions & 35 deletions api/apidata.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
package api

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
Expand All @@ -25,12 +25,17 @@ const (
videoExtractor = "https://youtube.com/get_video_info?video_id="
)

type stream map[string]string

//Youtube Downloader Data file.
type RawVideoData struct {
Title string `json:"title"`
Author string `json:"author"`
Status string `json:"status"`
URLEncodedFmtStreamMap string `json:"url_encoded_fmt_stream_map"`
Title string `json:"title"`
Author string `json:"author"`
Status string `json:"status"`
URLEncodedFmtStreamMap []stream `json:"url_encoded_fmt_stream_map"`
VideoId string
VideoInfo string
Vlength float64
}

//gets the Video ID from youtube url
Expand All @@ -54,7 +59,9 @@ func APIGetVideoStream(format, id, path string, bitrate uint) (err error) {
var decodedVideo []string //decoded video data

//Get Video Data stream
video.VideoId = id
videoUrl := videoExtractor + id
video.VideoInfo = videoUrl
resp, er := http.Get(videoUrl)
if er != nil {
logrus.Errorf("Error in GET request: %v", er)
Expand All @@ -72,50 +79,79 @@ func APIGetVideoStream(format, id, path string, bitrate uint) (err error) {
return nil
}

//Process Video stream
video.URLEncodedFmtStreamMap = output.Get("url_encoded_fmt_stream_map")
video.Author = output.Get("author")
video.Title = output.Get("title")
video.Status = output.Get("status")

//Decode Video
outputStreams := strings.Split(video.URLEncodedFmtStreamMap, ",")
for cur, raw_data := range outputStreams {
//decoding raw data stream
dec_data, err := url.ParseQuery(raw_data)
status, ok := output["status"]
if !ok {
err = fmt.Errorf("No response status in server")
return err
}
if status[0] == "fail" {
reason, ok := answer["reason"]
if ok {
err = fmt.Errorf("'fail' response status found in the server, reason: '%s'", reason[0])
} else {
err = errors.New(fmt.Sprint("'fail' response status found in the server, no reason given"))
}
return err
}
if status[0] != "ok" {
err = fmt.Errorf("non-success response status found in the server (status: '%s')", status)
return err
}

// read the streams map
video.Author = output["author"][0]
video.Title = output["title"][0]
video.URLEncodedFmtStreamMap, ok = output.Get("url_encoded_fmt_stream_map")
if !ok {
err = errors.New(fmt.Sprint("no stream map found in the server"))
return err
}

// read and decode streams.
streamsList := strings.Split(video.URLEncodedFmtStreamMap[0], ",")
var streams []stream
for streamPos, streamRaw := range streamsList {
streamQry, err := url.ParseQuery(streamRaw)
if err != nil {
logrus.Errorf("Error Decoding Video data: %d, %v", cur, err)
logrus.Infof("An error occured while decoding one of the video's streams: stream %d: %s\n", streamPos, err)
continue
}

data := map[string]string{
"quality": dec_data.Get("quality"),
"type": dec_data.Get("type"),
"url": dec_data.Get("url"),
"sig": dec_data.Get("sig"),
"title": video.Title,
"author": video.Author,
"format": dec_data.Get("format"),
var sig string
if _, exist := streamQry["sig"]; exist {
sig = streamQry["sig"][0]
}

str, _ := json.Marshal(data)
decodedVideo = append(decodedVideo, string(str))
//logrus.Infof("\nDecoded %d bytes of %q, in %q format", len(decodedVideo), dec_data.Get("quality"), dec_data.Get("format"))
streams = append(streams, stream{
"quality": streamQry["quality"][0],
"type": streamQry["type"][0],
"url": streamQry["url"][0],
"sig": sig,
"title": output["title"][0],
"author": output["author"][0],
})
logrus.Infof("Stream found: quality '%s', format '%s'", streamQry["quality"][0], streamQry["type"][0])
}

//Convert and Download video data
video.URLEncodedFmtStreamMap = streams
//Download Video stream to file
vstream := streams[0]
url := vstream["url"] + "&signature" + vstream["sig"]
logrus.Infof("Downloading file to %s", file)

//create output file name and set path properly.
file := path + video.Title + video.Author
if format == "mp3" {
file = file + ".mp3"
err = ApiConvertVideo(file, id, format, bitrate, decodedVideo)
if err != nil {
logrus.Errorf("Error downloading audio: %v", err)
}

} else { //defaults to flv format for video files.)
file = file + ".flv"
}

err = APIConvertVideo(file, id, format, bitrate, decodedVideo)
if err != nil {
logrus.Errorf("Error downloading video: %v", err)
if err := ApiDownloadVideo(file, url, video); err != nil {
logrus.Errorf("Error downloading video: %v", v)
}
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion ytd.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func main() {
defer pprof.StopCPUProfile()
}
runtime.SetBlockProfileRate(20)

if path == "" {
path, _ = os.Getwd()
}
Expand Down

0 comments on commit c807884

Please sign in to comment.