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

Commit 1c0f04f

Browse files
author
Nyah Check
committed
Fixes to API video extraction framework.
1 parent fcd240f commit 1c0f04f

File tree

2 files changed

+155
-105
lines changed

2 files changed

+155
-105
lines changed

api/apidata.go

Lines changed: 126 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66

77
package api
88

9-
import (
9+
import (
10+
"bytes"
11+
"encoding/json"
12+
"errors"
1013
"fmt"
1114
"io/ioutil"
1215
"net/http"
@@ -18,7 +21,23 @@ import (
1821
"google.golang.org/api/youtube/v3"
1922
)
2023

24+
25+
//const variables
26+
const (
27+
28+
//Video extractor
29+
videoExtractor = "http://youtube.com/get_video_info?video_id="
30+
)
31+
2132
//Youtube Downloader Data file.
33+
type RawVideoData struct {
34+
Title string `json:"title"`
35+
Author string `json:"author`
36+
Status string `json:"status"`
37+
URLEncodedFmtStreamMap map[string][]string `json:"url_encoded_fmt_stream_map"`
38+
}
39+
40+
}
2241
type ApiData struct {
2342
FileName string
2443
Title string
@@ -33,16 +52,17 @@ type ApiData struct {
3352
//gets the Video ID from youtube url
3453
func getVideoId(url string) ( string, error) {
3554

36-
s := strings.Split(url, "?v="))
55+
s := strings.Split(url, "?v=")
3756
s = strings.Split(s[1], "&")
3857
if len(s[0]) == 0 {
39-
s[0], error.New("Empty string)
58+
return s[0], errors.New("Empty string")
4059
}
4160

4261
return s[0], nil
4362
}
4463

4564

65+
4666
func printVideosListResults(response *youtube.VideoListResponse) {
4767
for _, item := range response.Items {
4868
fmt.Println(item.Id, ": ", item.Snippet.Title)
@@ -60,141 +80,148 @@ func videosListById(service *youtube.Service, part string, id string) {
6080
printVideosListResults(response)
6181
}
6282

63-
videosListById(service, "snippet,contentDetails,statistics", "Ks-_Mh1QhMc")
64-
65-
6683

6784

85+
//Gets Video Data from Youtube URL
6886
func APIGetVideoStream(service youtube.Service, url string)(videoData []byte, err error) {
87+
88+
videoStream := new(RawVideoData)
6989

7090
//Gets video Id
7191
id , err := getVideoId(url)
7292
auth.HandleError(err, "Invalid youtube URL.")
7393

74-
//Get Video response stream
75-
videosListById(service, "snippet,contentDetails,liveStreamingDetails, fileDetails", id)//fileDetails part not permitted.
94+
//Get Video Data stream
95+
videoUrl := videoExtractor + id
96+
resp, er := http.Get(videoUrl)
97+
auth.HandleError(er, "Error in GET request)
98+
defer resp.Body.Close()
99+
out, e := ioutil.ReadAll(resp.Body)
100+
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)
103+
}
104+
//Extract Video information.
105+
videoInfo := videosListById(service, "snippet,contentDetails", id)//fileDetails part not permitted.
76106

77107
//Get Data stream from video response
78-
108+
if err = json.Unmarshal(out, &videoStream); err != nil {
109+
logrus.Errorf("Error JSON Unmarshall: %v", err)
110+
}
79111

80112
//Download data stream to memory.
81113

82114
//convert video file to flv or mp3
83115

84116

117+
}
85118

86119

87-
//retrieve uploads
88-
func main() {
89-
flag.Parse()
90120

91-
client, err := buildOAuthHTTPClient(youtube.YoutubeReadonlyScope)
92-
if err != nil {
93-
log.Fatalf("Error building OAuth client: %v", err)
94-
}
121+
func ApiDownloadVideo() {
122+
95123

96-
service, err := youtube.New(client)
124+
}
125+
126+
127+
128+
func decodeVideoInfo(response string) (streams streamList, err error) {
129+
// decode
130+
131+
answer, err := url.ParseQuery(response)
97132
if err != nil {
98-
log.Fatalf("Error creating YouTube client: %v", err)
133+
err = fmt.Errorf("parsing the server's answer: '%s'", err)
134+
return
99135
}
100136

101-
// Start making YouTube API calls.
102-
// Call the channels.list method. Set the mine parameter to true to
103-
// retrieve the playlist ID for uploads to the authenticated user's
104-
// channel.
105-
call := service.Channels.List("contentDetails").Mine(true)
137+
// check the status
106138

107-
response, err := call.Do()
139+
err = ensureFields(answer, []string{"status", "url_encoded_fmt_stream_map", "title", "author"})
108140
if err != nil {
109-
// The channels.list method call returned an error.
110-
log.Fatalf("Error making API call to list channels: %v", err.Error())
141+
err = fmt.Errorf("Missing fields in the server's answer: '%s'", err)
142+
return
111143
}
112144

113-
for _, channel := range response.Items {
114-
playlistId := channel.ContentDetails.RelatedPlaylists.Uploads
115-
// Print the playlist ID for the list of uploaded videos.
116-
fmt.Printf("Videos in list %s\r\n", playlistId)
117-
118-
nextPageToken := ""
119-
for {
120-
// Call the playlistItems.list method to retrieve the
121-
// list of uploaded videos. Each request retrieves 50
122-
// videos until all videos have been retrieved.
123-
playlistCall := service.PlaylistItems.List("snippet").
124-
PlaylistId(playlistId).
125-
MaxResults(50).
126-
PageToken(nextPageToken)
127-
128-
playlistResponse, err := playlistCall.Do()
129-
130-
if err != nil {
131-
// The playlistItems.list method call returned an error.
132-
log.Fatalf("Error fetching playlist items: %v", err.Error())
133-
}
134-
135-
for _, playlistItem := range playlistResponse.Items {
136-
title := playlistItem.Snippet.Title
137-
videoId := playlistItem.Snippet.ResourceId.VideoId
138-
fmt.Printf("%v, (%v)\r\n", title, videoId)
139-
}
140-
141-
// Set the token to retrieve the next page of results
142-
// or exit the loop if all results have been retrieved.
143-
nextPageToken = playlistResponse.NextPageToken
144-
if nextPageToken == "" {
145-
break
146-
}
147-
fmt.Println()
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"))
148152
}
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
149158
}
150-
}
151159

152-
func ApiDownloadVideo() {
160+
log("Server answered with a success code")
153161

162+
/*
163+
for k, v := range answer {
164+
log("%s: %#v", k, v)
165+
}
166+
*/
154167

155-
}main() {
156-
flag.Parse()
168+
// read the streams map
157169

158-
if *filename == "" {
159-
log.Fatalf("You must provide a filename of a video file to upload")
160-
}
170+
stream_map := answer["url_encoded_fmt_stream_map"]
161171

162-
client, err := buildOAuthHTTPClient(youtube.YoutubeUploadScope)
163-
if err != nil {
164-
log.Fatalf("Error building OAuth client: %v", err)
165-
}
172+
// read each stream
166173

167-
service, err := youtube.New(client)
168-
if err != nil {
169-
log.Fatalf("Error creating YouTube client: %v", err)
170-
}
174+
streams_list := strings.Split(stream_map[0], ",")
171175

172-
upload := &youtube.Video{
173-
Snippet: &youtube.VideoSnippet{
174-
Title: *title,
175-
Description: *description,
176-
CategoryId: *category,
177-
},
178-
Status: &youtube.VideoStatus{PrivacyStatus: *privacy},
179-
}
176+
log("Found %d streams in answer", len(streams_list))
180177

181-
// The API returns a 400 Bad Request response if tags is an empty string.
182-
if strings.Trim(*keywords, "") != "" {
183-
upload.Snippet.Tags = strings.Split(*keywords, ",")
184-
}
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)
185210

186-
call := service.Videos.Insert("snippet,status", upload)
211+
quality := stream.Quality()
212+
if quality == QUALITY_UNKNOWN {
213+
log("Found unknown quality '%s'", stream["quality"])
214+
}
187215

188-
file, err := os.Open(*filename)
189-
defer file.Close()
190-
if err != nil {
191-
log.Fatalf("Error opening %v: %v", *filename, err)
192-
}
216+
format := stream.Format()
217+
if format == FORMAT_UNKNOWN {
218+
log("Found unknown format '%s'", stream["type"])
219+
}
193220

194-
response, err := call.Media(file).Do()
195-
if err != nil {
196-
log.Fatalf("Error making YouTube API call: %v", err)
221+
log("Stream found: quality '%s', format '%s'", quality, format)
197222
}
198-
fmt.Printf("Upload successful! Video ID: %v\n", response.Id)
199-
}
200223

224+
log("Successfully decoded %d streams", len(streams))
225+
226+
return
227+
}

simple.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
package main
66

77
import (
8+
"encoding/json"
89
"fmt"
9-
//"io/ioutil"
10-
"log"
10+
"io/ioutil"
11+
//"log"
1112
"net/http"
13+
14+
"github.com/Sirupsen/logrus"
1215

1316
"google.golang.org/api/googleapi/transport"
1417
youtube "google.golang.org/api/youtube/v3"
@@ -18,25 +21,45 @@ const developerKey = "AIzaSyCZSy5sOGsZrOrI0vLtowf_VJ-tl_USzNE"
1821

1922
func main() {
2023

24+
videoExtractor := "https://youtube.com/get_video_info?video_id="
25+
var dat map[string]interface{}
26+
id := "Ks-_Mh1QhMc"
27+
28+
2129
client := &http.Client{
2230
Transport: &transport.APIKey{Key: developerKey},
2331
}
2432

2533
service, err := youtube.New(client)
2634
if err != nil {
27-
log.Fatalf("Error creating new YouTube client: %v", err)
35+
logrus.Fatalf("Error creating new YouTube client: %v", err)
2836
}
2937

3038
// Make GET request to Youtube API.
31-
call := service.Videos.List("snippet, recordingDetails")
32-
call.Id("Ks-_Mh1QhMc")
39+
call := service.Videos.List("snippet, contentDetails, liveStreamingDetails, player")
40+
call.Id(id)
3341
resp, err := call.Do()
3442
if err != nil {
35-
log.Fatalf("Error getting Video response: %v", err)
43+
logrus.Fatalf("Error getting Video response: %v", err)
3644
}
3745
for cnt, item := range resp.Items {
3846
fmt.Printf("\n %d: %+v\n", cnt, item)
3947
}
4048

49+
logrus.Infof("Starting the Video extration process.")
50+
51+
//Get Video Data stream
52+
videoUrl := videoExtractor + id
53+
res, er := http.Get(videoUrl)
54+
logrus.Fatalf("Error in GET request: %v", er)
55+
defer res.Body.Close()
56+
out, e := ioutil.ReadAll(res.Body)
57+
logrus.Fatalf("Error reading video data", e)
58+
if err = json.Unmarshal(out, &dat); err != nil {
59+
logrus.Errorf("Error JSON Unmarshall: %v", err)
60+
}
61+
62+
fmt.Println(dat)
63+
4164
return
4265
}

0 commit comments

Comments
 (0)