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

Commit c004172

Browse files
author
Nyah Check
committed
Added video data stream decoding.
1 parent 9edca76 commit c004172

File tree

2 files changed

+68
-115
lines changed

2 files changed

+68
-115
lines changed

api/apidata.go

Lines changed: 53 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ package api
88

99
import (
1010
"bytes"
11-
"encoding/json"
1211
"errors"
1312
"fmt"
1413
"io/ioutil"
1514
"net/http"
15+
"net/url"
1616
"os"
1717
"strings"
1818

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

88-
videoStream := new(RawVideoData)
88+
video := new(RawVideoData)//raw video data
89+
var decodedVideo []string //decoded video data
8990

9091
//Gets video Id
9192
id , err := getVideoId(url)
@@ -98,130 +99,71 @@ func APIGetVideoStream(service youtube.Service, url string)(videoData []byte, er
9899
defer resp.Body.Close()
99100
out, e := ioutil.ReadAll(resp.Body)
100101
auth.HandleError(e, "Error reading video data")
101-
if err = json.Unmarshal(out, &a.output); err != nil {
102-
logrus.Errorf("Error JSON Unmarshall: %v", err)
102+
103+
output, er := url.ParseQuery(out)
104+
if e != nil {
105+
logrus.Fatalf("Error Parsing video byte stream", e)
103106
}
104-
//Extract Video information.
105-
videoInfo := videosListById(service, "snippet,contentDetails", id)//fileDetails part not permitted.
107+
//fmt.Println(string(output))
108+
109+
//Process Video stream
110+
video.URLEncodedFmtStreamMap = output["url_encoded_fmt_stream_map"]
111+
video.Author = output["author"]
112+
video.Title = output["title"]
113+
video.Status = output["status"]
106114

107-
//Get Data stream from video response
108-
if err = json.Unmarshal(out, &videoStream); err != nil {
109-
logrus.Errorf("Error JSON Unmarshall: %v", err)
115+
//Decode Video
116+
outputStreams := strings.Split(video.URLEncodedFmtStreamMap[0], ",")
117+
for cur, raw_data := range outputStream {
118+
//decoding raw data stream
119+
dec_data, err := url.ParseQuery(raw_data)
120+
if err != nil {
121+
logrus.Errorf("Error Decoding Video data: %d, %v", cur, err)
122+
continue
123+
}
124+
125+
data := map[string]string{
126+
"quality": dec_data["quality"][0],
127+
"type": dec_data["type"][0],
128+
"url": dec_data["url"][0],
129+
"sig": dec_data["sig"][0],
130+
"title": video.Title,
131+
"author": video.Author,
132+
"format": dec_data["format"][0],
133+
}
134+
135+
decodedVideo = append(decodedVideo, data)
136+
logrus.Infof("\nDecoded %d bytes of '%s", in '%s' format, len(decodedVideo), dec_data["quality"][0], dec_data["format"][0])
110137
}
111138

112-
//Download data stream to memory.
113139

114-
//convert video file to flv or mp3
115-
116-
117-
}
118-
119-
120-
121-
func ApiDownloadVideo() {
122-
123-
140+
//Download data stream to memory and convert to proper format
141+
//NOTE: Use ffmpeg go bindings for this use case.
142+
124143
}
125144

126145

127146

128-
func decodeVideoInfo(response string) (streams streamList, err error) {
129-
// decode
130-
131-
answer, err := url.ParseQuery(response)
132-
if err != nil {
133-
err = fmt.Errorf("parsing the server's answer: '%s'", err)
134-
return
135-
}
147+
func APIDownloadVideo(videoStream map[string][]string) ([]byte, err) {
148+
func (stream stream) download(out io.Writer) error {
149+
url := stream.Url()
136150

137-
// check the status
151+
log("Downloading stream from '%s'", url)
138152

139-
err = ensureFields(answer, []string{"status", "url_encoded_fmt_stream_map", "title", "author"})
153+
resp, err := http.Get(url)
140154
if err != nil {
141-
err = fmt.Errorf("Missing fields in the server's answer: '%s'", err)
142-
return
155+
return fmt.Errorf("requesting stream: %s", err)
143156
}
144-
145-
status := answer["status"]
146-
if status[0] == "fail" {
147-
reason, ok := answer["reason"]
148-
if ok {
149-
err = fmt.Errorf("'fail' response status found in the server's answer, reason: '%s'", reason[0])
150-
} else {
151-
err = errors.New(fmt.Sprint("'fail' response status found in the server's answer, no reason given"))
152-
}
153-
return
154-
}
155-
if status[0] != "ok" {
156-
err = fmt.Errorf("non-success response status found in the server's answer (status: '%s')", status)
157-
return
158-
}
159-
160-
log("Server answered with a success code")
161-
162-
/*
163-
for k, v := range answer {
164-
log("%s: %#v", k, v)
157+
defer resp.Body.Close()
158+
if resp.StatusCode != 200 {
159+
return fmt.Errorf("reading answer: non 200 status code received: '%s'", err)
165160
}
166-
*/
167-
168-
// read the streams map
169-
170-
stream_map := answer["url_encoded_fmt_stream_map"]
171-
172-
// read each stream
173-
174-
streams_list := strings.Split(stream_map[0], ",")
175-
176-
log("Found %d streams in answer", len(streams_list))
177-
178-
for stream_pos, stream_raw := range streams_list {
179-
stream_qry, err := url.ParseQuery(stream_raw)
180-
if err != nil {
181-
log(fmt.Sprintf("An error occured while decoding one of the video's stream's information: stream %d: %s\n", stream_pos, err))
182-
continue
183-
}
184-
err = ensureFields(stream_qry, []string{"quality", "type", "url"})
185-
if err != nil {
186-
log(fmt.Sprintf("Missing fields in one of the video's stream's information: stream %d: %s\n", stream_pos, err))
187-
continue
188-
}
189-
/* dumps the raw streams
190-
log(fmt.Sprintf("%v\n", stream_qry))
191-
*/
192-
stream := stream{
193-
"quality": stream_qry["quality"][0],
194-
"type": stream_qry["type"][0],
195-
"url": stream_qry["url"][0],
196-
"sig": "",
197-
"title": answer["title"][0],
198-
"author": answer["author"][0],
199-
}
200-
201-
if sig, exists := stream_qry["sig"]; exists { // old one
202-
stream["sig"] = sig[0]
203-
}
204-
205-
if sig, exists := stream_qry["s"]; exists { // now they use this
206-
stream["sig"] = sig[0]
207-
}
208-
209-
streams = append(streams, stream)
210-
211-
quality := stream.Quality()
212-
if quality == QUALITY_UNKNOWN {
213-
log("Found unknown quality '%s'", stream["quality"])
214-
}
215-
216-
format := stream.Format()
217-
if format == FORMAT_UNKNOWN {
218-
log("Found unknown format '%s'", stream["type"])
219-
}
220-
221-
log("Stream found: quality '%s', format '%s'", quality, format)
161+
length, err := io.Copy(out, resp.Body)
162+
if err != nil {
163+
return fmt.Errorf("saving file: %s (%d bytes copied)", err, length)
222164
}
223165

224-
log("Successfully decoded %d streams", len(streams))
166+
log("Downloaded %d bytes", length)
225167

226-
return
168+
return nil
227169
}

cmd/ytd/ytd.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ var (
5353
maxResults = flag.Int64("max-results", 25, "Max YouTube results")
5454
)
5555

56+
//Youtube Downloader Data file.
57+
type ApiData struct {
58+
FileName string
59+
Title string
60+
description string
61+
category string
62+
keywords string
63+
privacy string
64+
DataStream []byte
65+
}
5666

5767
func init() {
5868
// parse flags
@@ -69,7 +79,7 @@ func init() {
6979
flag.Parse()
7080

7181
if version {
72-
fmt.Printf("%s", VERSION)
82+
logrus.Infof("%s", VERSION)
7383
os.Exit(0)
7484
}
7585

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

99+
89100
//channelsListByUsername(service, "snippet,contentDetails,statistics", "GoogleDevelopers")
90101
}
91102

92103
func usageAndExit(message string, exitCode int) {
93104
if message != "" {
94-
fmt.Fprintf(os.Stderr, message)
95-
fmt.Fprintf(os.Stderr, "\n\n")
105+
logrus.Infof(os.Stderr, message)
106+
logrus.Infof(os.Stderr, "\n\n")
96107
}
97108
flag.Usage()
98-
fmt.Fprintf(os.Stderr, "\n")
109+
logrus.Infof(os.Stderr, "\n")
99110
os.Exit(exitCode)
100111
}

0 commit comments

Comments
 (0)