Skip to content
This repository was archived by the owner on Oct 6, 2024. It is now read-only.

Commit

Permalink
Added video data stream decoding.
Browse files Browse the repository at this point in the history
Nyah Check committed Aug 5, 2017

Verified

This commit was signed with the committer’s verified signature.
poyzannur Poyzan
1 parent 9edca76 commit c004172
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
@@ -8,11 +8,11 @@ package api

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

@@ -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)
@@ -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
@@ -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
@@ -69,7 +79,7 @@ func init() {
flag.Parse()

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

@@ -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.