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

Commit

Permalink
Added video data stream decoding.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nyah Check committed Aug 5, 2017
1 parent 9edca76 commit c004172
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 115 deletions.
164 changes: 53 additions & 111 deletions api/apidata.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ package api

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"

Expand Down Expand Up @@ -85,7 +85,8 @@ func videosListById(service *youtube.Service, part string, id string) {
//Gets Video Data from Youtube URL
func APIGetVideoStream(service youtube.Service, url string)(videoData []byte, err error) {

videoStream := new(RawVideoData)
video := new(RawVideoData)//raw video data
var decodedVideo []string //decoded video data

//Gets video Id
id , err := getVideoId(url)
Expand All @@ -98,130 +99,71 @@ func APIGetVideoStream(service youtube.Service, url string)(videoData []byte, er
defer resp.Body.Close()
out, e := ioutil.ReadAll(resp.Body)
auth.HandleError(e, "Error reading video data")
if err = json.Unmarshal(out, &a.output); err != nil {
logrus.Errorf("Error JSON Unmarshall: %v", err)

output, er := url.ParseQuery(out)
if e != nil {
logrus.Fatalf("Error Parsing video byte stream", e)
}
//Extract Video information.
videoInfo := videosListById(service, "snippet,contentDetails", id)//fileDetails part not permitted.
//fmt.Println(string(output))

//Process Video stream
video.URLEncodedFmtStreamMap = output["url_encoded_fmt_stream_map"]
video.Author = output["author"]
video.Title = output["title"]
video.Status = output["status"]

//Get Data stream from video response
if err = json.Unmarshal(out, &videoStream); err != nil {
logrus.Errorf("Error JSON Unmarshall: %v", err)
//Decode Video
outputStreams := strings.Split(video.URLEncodedFmtStreamMap[0], ",")
for cur, raw_data := range outputStream {
//decoding raw data stream
dec_data, err := url.ParseQuery(raw_data)
if err != nil {
logrus.Errorf("Error Decoding Video data: %d, %v", cur, err)
continue
}

data := map[string]string{
"quality": dec_data["quality"][0],
"type": dec_data["type"][0],
"url": dec_data["url"][0],
"sig": dec_data["sig"][0],
"title": video.Title,
"author": video.Author,
"format": dec_data["format"][0],
}

decodedVideo = append(decodedVideo, data)
logrus.Infof("\nDecoded %d bytes of '%s", in '%s' format, len(decodedVideo), dec_data["quality"][0], dec_data["format"][0])
}

//Download data stream to memory.

//convert video file to flv or mp3


}



func ApiDownloadVideo() {


//Download data stream to memory and convert to proper format
//NOTE: Use ffmpeg go bindings for this use case.

}



func decodeVideoInfo(response string) (streams streamList, err error) {
// decode

answer, err := url.ParseQuery(response)
if err != nil {
err = fmt.Errorf("parsing the server's answer: '%s'", err)
return
}
func APIDownloadVideo(videoStream map[string][]string) ([]byte, err) {
func (stream stream) download(out io.Writer) error {
url := stream.Url()

// check the status
log("Downloading stream from '%s'", url)

err = ensureFields(answer, []string{"status", "url_encoded_fmt_stream_map", "title", "author"})
resp, err := http.Get(url)
if err != nil {
err = fmt.Errorf("Missing fields in the server's answer: '%s'", err)
return
return fmt.Errorf("requesting stream: %s", err)
}

status := answer["status"]
if status[0] == "fail" {
reason, ok := answer["reason"]
if ok {
err = fmt.Errorf("'fail' response status found in the server's answer, reason: '%s'", reason[0])
} else {
err = errors.New(fmt.Sprint("'fail' response status found in the server's answer, no reason given"))
}
return
}
if status[0] != "ok" {
err = fmt.Errorf("non-success response status found in the server's answer (status: '%s')", status)
return
}

log("Server answered with a success code")

/*
for k, v := range answer {
log("%s: %#v", k, v)
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("reading answer: non 200 status code received: '%s'", err)
}
*/

// read the streams map

stream_map := answer["url_encoded_fmt_stream_map"]

// read each stream

streams_list := strings.Split(stream_map[0], ",")

log("Found %d streams in answer", len(streams_list))

for stream_pos, stream_raw := range streams_list {
stream_qry, err := url.ParseQuery(stream_raw)
if err != nil {
log(fmt.Sprintf("An error occured while decoding one of the video's stream's information: stream %d: %s\n", stream_pos, err))
continue
}
err = ensureFields(stream_qry, []string{"quality", "type", "url"})
if err != nil {
log(fmt.Sprintf("Missing fields in one of the video's stream's information: stream %d: %s\n", stream_pos, err))
continue
}
/* dumps the raw streams
log(fmt.Sprintf("%v\n", stream_qry))
*/
stream := stream{
"quality": stream_qry["quality"][0],
"type": stream_qry["type"][0],
"url": stream_qry["url"][0],
"sig": "",
"title": answer["title"][0],
"author": answer["author"][0],
}

if sig, exists := stream_qry["sig"]; exists { // old one
stream["sig"] = sig[0]
}

if sig, exists := stream_qry["s"]; exists { // now they use this
stream["sig"] = sig[0]
}

streams = append(streams, stream)

quality := stream.Quality()
if quality == QUALITY_UNKNOWN {
log("Found unknown quality '%s'", stream["quality"])
}

format := stream.Format()
if format == FORMAT_UNKNOWN {
log("Found unknown format '%s'", stream["type"])
}

log("Stream found: quality '%s', format '%s'", quality, format)
length, err := io.Copy(out, resp.Body)
if err != nil {
return fmt.Errorf("saving file: %s (%d bytes copied)", err, length)
}

log("Successfully decoded %d streams", len(streams))
log("Downloaded %d bytes", length)

return
return nil
}
19 changes: 15 additions & 4 deletions cmd/ytd/ytd.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ var (
maxResults = flag.Int64("max-results", 25, "Max YouTube results")
)

//Youtube Downloader Data file.
type ApiData struct {
FileName string
Title string
description string
category string
keywords string
privacy string
DataStream []byte
}

func init() {
// parse flags
Expand All @@ -69,7 +79,7 @@ func init() {
flag.Parse()

if version {
fmt.Printf("%s", VERSION)
logrus.Infof("%s", VERSION)
os.Exit(0)
}

Expand All @@ -86,15 +96,16 @@ func main() {
service, err = auth.CreateYoutubeService(ctx)
auth.HandleError(err, "Error creating YouTube client")


//channelsListByUsername(service, "snippet,contentDetails,statistics", "GoogleDevelopers")
}

func usageAndExit(message string, exitCode int) {
if message != "" {
fmt.Fprintf(os.Stderr, message)
fmt.Fprintf(os.Stderr, "\n\n")
logrus.Infof(os.Stderr, message)
logrus.Infof(os.Stderr, "\n\n")
}
flag.Usage()
fmt.Fprintf(os.Stderr, "\n")
logrus.Infof(os.Stderr, "\n")
os.Exit(exitCode)
}

0 comments on commit c004172

Please sign in to comment.