Skip to content

Commit

Permalink
update: The search function has been dec and the Playlist listing fea…
Browse files Browse the repository at this point in the history
…ture has been added (The channel has been defined but not written yet.)
  • Loading branch information
yigit433 committed Feb 10, 2022
1 parent a4eadb2 commit 00c2d2c
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 54 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import (
)

func main() {
res := youtube.SearchVideos("Jim Yosef Hate You")
res := youtube.Search("Nora & Chris, Drenchill Remedy", youtube.SearchOptions{
Type: "video",
Limit: 15
})

fmt.Println(res)
}
Expand Down
64 changes: 64 additions & 0 deletions parsers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package youtubego

import "fmt"

func ParsePlaylist(data interface{}) PlaylistParser {
if data != nil {
return PlaylistParser{
IsSuccess: false,
}
} else {
return PlaylistParser{
IsSuccess: false,
}
}
}

func ParseChannel(data interface{}) ChannelParser {
if data != nil {
navEndpoint := data.(map[string]interface{})["navigationEndpoint"]
url := fmt.Sprintf("https://www.youtube.com%s", navEndpoint.(map[string]interface{})["browseEndpoint"].(map[string]interface{})["canonicalBaseUrl"] || navEndpoint.(map[string]interface{})["commandMetadata"].(map[string]interface{})["webCommandMetadata"].(map[string]interface{})["url"])
thumbnail := data.(map[string]interface{})["thumbnail"].(map[string]interface{})["thumbnails"]

var out ChannelParser
out = ChannelParser{
Id: data.(map[string]interface{})["channelId"].(string),
Url: url,
Name: data.(map[string]interface{})["title"].(map[string]interface{})["simpleText"].(string),
Icon: thumbnail.([]interface{})[len(thumbnail.([]interface{}))-1],
Subscribers: data.(map[string]interface{})["subscriberCountText"].(map[string]interface{})["simpleText"],
}
} else {
return ChannelParser{
IsSuccess: false,
}
}
}

func ParseVideo(data interface{}) VideoParser {
if data != nil {
thumbnail := data.(map[string]interface{})["thumbnail"].(map[string]interface{})["thumbnails"].([]interface{})

var out VideoParser
out = VideoParser{
Video: Video{
Id: data.(map[string]interface{})["videoId"].(string),
Title: data.(map[string]interface{})["title"].(map[string]interface{})["runs"].([]interface{})[0].(map[string]interface{})["text"].(string),
Url: fmt.Sprintf("https://www.youtube.com/watch?v=%s", data.(map[string]interface{})["videoId"].(string)),
Thumbnail: Thumbnail{
Id: data.(map[string]interface{})["videoId"].(string),
Url: thumbnail[len(thumbnail)-1].(map[string]interface{})["url"].(string),
Width: fmt.Sprintf("%v", thumbnail[len(thumbnail)-1].(map[string]interface{})["width"]),
Height: fmt.Sprintf("%v", thumbnail[len(thumbnail)-1].(map[string]interface{})["height"]),
},
},
IsSuccess: true,
}

return out
} else {
return VideoParser{
IsSuccess: false,
}
}
}
43 changes: 36 additions & 7 deletions types.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,49 @@
package youtubego

type Thumbnail struct {
Id string
Width string
Height string
Url string
Id, Width, Height, Url string
}

type Video struct {
Thumbnail
Id string
Title string
Url string
Id, Title, Url string
}

type VideoParser struct {
Video
IsSuccess bool
}

type Channel struct {
Thumbnail
Id, Url, Name, Subscribers string
Verified bool
}

type ChannelParser struct {
Channel
IsSuccess bool
}

type Playlist struct {
Thumbnail
Channel
Id, title string
Videos int
}

type PlaylistParser struct {
Playlist
IsSuccess bool
}

type SearchResult struct {
Video
Playlist
Channels
}

type SearchOptions struct {
Limit int
Type string
}
92 changes: 48 additions & 44 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"strings"
)

func CreateRequest(searchWord string) []Video {
func CreateRequest(searchWord string, options SearchOptions) []SearchResult {
Url, err := url.Parse("http://youtube.com/results")

if err != nil {
Expand All @@ -19,7 +19,14 @@ func CreateRequest(searchWord string) []Video {

query := url.Values{}
query.Add("search_query", searchWord)
query.Add("sp", "EgIQAQ%253D%253D")

if strings.ToLower(options.Type) == "video" {
query.Add("sp", "EgIQAQ%253D%253D")
} else if strings.ToLower(options.Type) == "playlist" {
query.Add("sp", "EgIQAw%253D%253D")
} else if strings.ToLower(options.Type) == "channel" {
query.Add("sp", "EgIQAg%253D%253D")
}

Url.RawQuery = query.Encode()

Expand All @@ -36,7 +43,18 @@ func CreateRequest(searchWord string) []Video {
log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
}
bodyResp, err := io.ReadAll(res.Body)
html := []byte(ParseHTML(string(bodyResp)))
if err != nil {
log.Fatalf("Cannot read the body stream.")
}

return ParseHTML(bodyResp, options.Limit)
}

func ParseHTML(html string, limit int) []SearchResult {
index := len(strings.Split(html, `{"itemSectionRenderer":`)) - 1
items := strings.Split(html, `{"itemSectionRenderer":`)[index]
parsed := strings.Split(items, `},{"continuationItemRenderer":{`)[0]
html := []byte(ParseHTML(string(parsed)))

var out map[string]interface{}
err = json.Unmarshal(html, &out)
Expand All @@ -45,51 +63,37 @@ func CreateRequest(searchWord string) []Video {
panic("Something went wrong, the problem was encountered while analyzing JSON!")
}
arr := out["contents"].([]interface{})
output := []Video{}
output := []SearchResult{}

for i := 0; len(arr) > i; i++ {
sdata := arr[i].(map[string]interface{})["videoRenderer"]
parsedVideo := ParseVideo(sdata)

if parsedVideo.IsSuccess {
output = append(output, parsedVideo.Video)
sdata := arr[i].(map[string]interface{})

if sdata["videoRenderer"] {
parsed := ParseVideo(sdata["videoRenderer"])

if parsed.IsSuccess {
output = append(output, &SearchResult{
Video: parsed.Video,
})
}
} else if sdata["playlistRenderer"] {
parsed := ParsePlaylist(sdata["playlistRenderer"])

if parsed.IsSuccess {
output = append(output, &SearchResult{
Playlist: parsed.Playlist,
})
}
} else if sdata["channelRenderer"] {
parsed := ParseVideo(sdata["channelRenderer"])

if parsed.IsSuccess {
output = append(output, &SearchResult{
Channel: parsed.Channel,
})
}
}
}

return output
}

func ParseHTML(html string) string {
index := len(strings.Split(html, `{"itemSectionRenderer":`)) - 1
items := strings.Split(html, `{"itemSectionRenderer":`)[index]

return strings.Split(items, `},{"continuationItemRenderer":{`)[0]
}

func ParseVideo(data interface{}) VideoParser {
if data != nil {
thumbnail := data.(map[string]interface{})["thumbnail"].(map[string]interface{})["thumbnails"].([]interface{})

var out VideoParser
out = VideoParser{
Video: Video{
Id: data.(map[string]interface{})["videoId"].(string),
Title: data.(map[string]interface{})["title"].(map[string]interface{})["runs"].([]interface{})[0].(map[string]interface{})["text"].(string),
Url: fmt.Sprintf("https://www.youtube.com/watch?v=%s", data.(map[string]interface{})["videoId"].(string)),
Thumbnail: Thumbnail{
Id: data.(map[string]interface{})["videoId"].(string),
Url: thumbnail[len(thumbnail)-1].(map[string]interface{})["url"].(string),
Width: fmt.Sprintf("%v", thumbnail[len(thumbnail)-1].(map[string]interface{})["width"]),
Height: fmt.Sprintf("%v", thumbnail[len(thumbnail)-1].(map[string]interface{})["height"]),
},
},
IsSuccess: true,
}

return out
} else {
return VideoParser{
IsSuccess: false,
}
}
}
4 changes: 2 additions & 2 deletions youtube.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package youtubego

func SearchVideos(searchq string) []Video {
res := CreateRequest(searchq)
func Search(searchq string, options SearchOptions) []interface{} {
res := CreateRequest(searchq, options)

return res
}

0 comments on commit 00c2d2c

Please sign in to comment.