mirror of
https://codeberg.org/Hyperpipe/hyperpipe-backend
synced 2024-12-06 19:26:30 +01:00
Added Genre
This commit is contained in:
+96
-30
@@ -1,11 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func GetThumbnails(j gjson.Result) []Thumbnail {
|
||||
|
||||
t := []Thumbnail{}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
j.ForEach(
|
||||
func(_, v gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
u, err := ParseUrl(v.Get("url").String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
t = append(t, Thumbnail{
|
||||
Url: u,
|
||||
Width: v.Get("width").Int(),
|
||||
Height: v.Get("height").Int(),
|
||||
})
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func TwoRowItemRenderer(t string, a gjson.Result) []Item {
|
||||
|
||||
r := []Item{}
|
||||
@@ -13,7 +50,9 @@ func TwoRowItemRenderer(t string, a gjson.Result) []Item {
|
||||
var id string
|
||||
|
||||
if t == "album" || t == "singles" {
|
||||
id = "menu.menuRenderer.items.#(menuNavigationItemRenderer.text.runs.0.text == Shuffle play).menuNavigationItemRenderer.navigationEndpoint.watchPlaylistEndpoint.playlistId"
|
||||
id = "menu.menuRenderer.items.#(menuNavigationItemRenderer" +
|
||||
".text.runs.0.text == Shuffle play).menuNavigationItemRenderer" +
|
||||
".navigationEndpoint.watchPlaylistEndpoint.playlistId"
|
||||
} else {
|
||||
id = "navigationEndpoint.browseEndpoint.browseId"
|
||||
}
|
||||
@@ -30,11 +69,18 @@ func TwoRowItemRenderer(t string, a gjson.Result) []Item {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
gid := j.Get(id).String()
|
||||
|
||||
if len(gid) > 2 && gid[:2] == "VL" {
|
||||
gid = gid[2:]
|
||||
}
|
||||
|
||||
r = append(r, Item{
|
||||
Id: j.Get(id).String(),
|
||||
Title: RunsText(j.Get("title")),
|
||||
Sub: RunsText(j.Get("subtitle")),
|
||||
Thumbnails: GetThumbnails(j.Get("thumbnailRenderer.musicThumbnailRenderer.thumbnail.thumbnails")),
|
||||
Id: gid,
|
||||
Title: RunsText(j.Get("title")),
|
||||
Sub: RunsText(j.Get("subtitle")),
|
||||
Thumbnails: GetThumbnails(j.Get("thumbnailRenderer" +
|
||||
".musicThumbnailRenderer.thumbnail.thumbnails")),
|
||||
})
|
||||
|
||||
}()
|
||||
@@ -48,25 +94,6 @@ func TwoRowItemRenderer(t string, a gjson.Result) []Item {
|
||||
return r
|
||||
}
|
||||
|
||||
func CarouselShelfRenderer(i gjson.Result) map[string]interface{} {
|
||||
|
||||
shelf := make(map[string]interface{})
|
||||
|
||||
shelf["title"] = RunsText(i.Get("header.musicCarouselShelfBasicHeaderRenderer.title"))
|
||||
|
||||
ct := i.Get("contents")
|
||||
|
||||
if ct.Get("#(musicTwoRowItemRenderer)").Exists() {
|
||||
shelf["contents"] = TwoRowItemRenderer("", ct)
|
||||
} else if ct.Get("#(musicResponsiveListItemRenderer)").Exists() {
|
||||
shelf["contents"] = ResponsiveListItemRenderer(ct)
|
||||
}
|
||||
|
||||
shelf["raw"] = ct.Value()
|
||||
|
||||
return shelf
|
||||
}
|
||||
|
||||
func ResponsiveListItemRenderer(s gjson.Result) []Item {
|
||||
|
||||
r := []Item{}
|
||||
@@ -82,14 +109,19 @@ func ResponsiveListItemRenderer(s gjson.Result) []Item {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("musicResponsiveListItemRenderer")
|
||||
flex := j.Get("flexColumns.#.musicResponsiveListItemFlexColumnRenderer.text.runs.0")
|
||||
flex := j.Get("flexColumns.#.musicResponsiveListItemFlexColumnRenderer" +
|
||||
".text.runs.0")
|
||||
|
||||
r = append(r, Item{
|
||||
Id: j.Get("playlistItemData.videoId").String(),
|
||||
Title: flex.Get("#(navigationEndpoint.watchEndpoint.videoId).text").String(),
|
||||
SubId: flex.Get("#.navigationEndpoint.browseEndpoint").Get("#(browseId).browseId").String(),
|
||||
Sub: flex.Get("#(navigationEndpoint.browseEndpoint.browseId).text").String(),
|
||||
Thumbnails: GetThumbnails(j.Get("thumbnail.musicThumbnailRenderer.thumbnail.thumbnails")),
|
||||
Id: j.Get("playlistItemData.videoId").String(),
|
||||
Title: flex.Get("#(navigationEndpoint.watchEndpoint" +
|
||||
".videoId).text").String(),
|
||||
SubId: flex.Get("#.navigationEndpoint.browseEndpoint" +
|
||||
".#(browseId).browseId").String(),
|
||||
Sub: flex.Get("#(navigationEndpoint.browseEndpoint" +
|
||||
".browseId).text").String(),
|
||||
Thumbnails: GetThumbnails(j.Get("thumbnail.musicThumbnailRenderer" +
|
||||
".thumbnail.thumbnails")),
|
||||
})
|
||||
|
||||
}()
|
||||
@@ -102,3 +134,37 @@ func ResponsiveListItemRenderer(s gjson.Result) []Item {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func NavigationButton(s gjson.Result) []Item {
|
||||
|
||||
r := []Item{}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
s.ForEach(
|
||||
func(_, v gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("musicNavigationButtonRenderer")
|
||||
|
||||
color := j.Get("solid.leftStripeColor").Uint() & 0xffffff
|
||||
|
||||
r = append(r, Item{
|
||||
Id: j.Get("clickCommand.browseEndpoint.params").String(),
|
||||
Title: RunsText(j.Get("buttonText")),
|
||||
Sub: fmt.Sprintf("#%06x", color),
|
||||
})
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -11,19 +11,9 @@ import (
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func Fetch(path string, data []byte, c string) (string, int, error) {
|
||||
func Fetch(path string, data []byte) (string, int, error) {
|
||||
|
||||
var query string
|
||||
|
||||
if c != "" {
|
||||
query = "&ctoken=" + c + "&continuation=" + c + "&type=next"
|
||||
} else {
|
||||
query = ""
|
||||
}
|
||||
|
||||
url := "https://music.youtube.com/youtubei/v1/" + path + "?key=AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30" + query + "&prettyPrint=false"
|
||||
|
||||
log.Println(url)
|
||||
url := "https://music.youtube.com/youtubei/v1/" + path + "?key=AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30&prettyPrint=false"
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
@@ -54,14 +44,14 @@ func Fetch(path string, data []byte, c string) (string, int, error) {
|
||||
return string(body), resp.StatusCode, nil
|
||||
}
|
||||
|
||||
func FetchBrowse(id string, c string, browse BrowseData) (string, int) {
|
||||
func FetchBrowse(id string, browse BrowseData) (string, int) {
|
||||
|
||||
data, err := json.Marshal(browse)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
raw, status, err := Fetch("browse", data, c)
|
||||
raw, status, err := Fetch("browse", data)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
@@ -70,39 +60,13 @@ func FetchBrowse(id string, c string, browse BrowseData) (string, int) {
|
||||
|
||||
}
|
||||
|
||||
func FetchHome(c string) (string, int) {
|
||||
|
||||
/* WIP */
|
||||
|
||||
id := "FEmusic_home"
|
||||
|
||||
if c != "" {
|
||||
id = ""
|
||||
}
|
||||
|
||||
log.Println(id)
|
||||
|
||||
context := GetTypeBrowse("home", id)
|
||||
|
||||
raw, status := FetchBrowse(id, c, context)
|
||||
|
||||
/*res, err := ParseHome(raw)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}*/
|
||||
|
||||
return raw, status
|
||||
}
|
||||
|
||||
func FetchExplore() (string, int) {
|
||||
|
||||
id := "FEmusic_explore"
|
||||
|
||||
log.Println(id)
|
||||
context := GetTypeBrowse("", id, "")
|
||||
|
||||
context := GetTypeBrowse("", id)
|
||||
|
||||
raw, status := FetchBrowse(id, "", context)
|
||||
raw, status := FetchBrowse(id, context)
|
||||
|
||||
res, err := ParseExplore(raw)
|
||||
if err != nil {
|
||||
@@ -112,26 +76,43 @@ func FetchExplore() (string, int) {
|
||||
return res, status
|
||||
}
|
||||
|
||||
func FetchMoods() (string, int) {
|
||||
|
||||
/* WIP */
|
||||
func FetchGenres() (string, int) {
|
||||
|
||||
id := "FEmusic_moods_and_genres"
|
||||
|
||||
log.Println(id)
|
||||
context := GetTypeBrowse("", id, "")
|
||||
|
||||
context := GetTypeBrowse("", id)
|
||||
raw, status := FetchBrowse(id, context)
|
||||
|
||||
raw, status := FetchBrowse(id, "", context)
|
||||
res, err := ParseGenres(raw)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
return raw, status
|
||||
return res, status
|
||||
}
|
||||
|
||||
func FetchGenre(param string) (string, int) {
|
||||
|
||||
id := "FEmusic_moods_and_genres_category"
|
||||
|
||||
context := GetTypeBrowse("", id, param)
|
||||
|
||||
raw, status := FetchBrowse(id, context)
|
||||
|
||||
res, err := ParseGenre(raw)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
|
||||
func FetchArtist(id string) (string, int) {
|
||||
|
||||
context := GetTypeBrowse("artist", id)
|
||||
context := GetTypeBrowse("artist", id, "")
|
||||
|
||||
raw, status := FetchBrowse(id, "", context)
|
||||
raw, status := FetchBrowse(id, context)
|
||||
|
||||
res, err := ParseArtist(raw)
|
||||
if err != nil {
|
||||
@@ -143,9 +124,9 @@ func FetchArtist(id string) (string, int) {
|
||||
|
||||
func FetchLyrics(id string) (string, int) {
|
||||
|
||||
context := GetTypeBrowse("lyrics", id)
|
||||
context := GetTypeBrowse("lyrics", id, "")
|
||||
|
||||
raw, status := FetchBrowse(id, "", context)
|
||||
raw, status := FetchBrowse(id, context)
|
||||
|
||||
res, err := ParseLyrics(raw)
|
||||
if err != nil {
|
||||
@@ -155,20 +136,11 @@ func FetchLyrics(id string) (string, int) {
|
||||
return res, status
|
||||
}
|
||||
|
||||
func FetchPlaylist(id string) (string, int) {
|
||||
|
||||
context := GetTypeBrowse("playlist", id)
|
||||
|
||||
raw, status := FetchBrowse(id, "", context)
|
||||
|
||||
return raw, status
|
||||
}
|
||||
|
||||
func FetchAlbum(id string) (string, int) {
|
||||
|
||||
context := GetTypeBrowse("album", id)
|
||||
context := GetTypeBrowse("album", id, "")
|
||||
|
||||
raw, status := FetchBrowse(id, "", context)
|
||||
raw, status := FetchBrowse(id, context)
|
||||
|
||||
url := gjson.Parse(raw).Get("microformat.microformatDataRenderer.urlCanonical").String()
|
||||
|
||||
@@ -186,7 +158,7 @@ func FetchNext(id string) (string, int) {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
raw, status, err := Fetch("next", data, "")
|
||||
raw, status, err := Fetch("next", data)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
@@ -24,14 +24,6 @@ func HandleHealth(c *fiber.Ctx) error {
|
||||
return c.SendStatus(204)
|
||||
}
|
||||
|
||||
func HandleHome(c *fiber.Ctx) error {
|
||||
defer calc(c.OriginalURL())()
|
||||
|
||||
res, status := FetchHome(c.Params("id"))
|
||||
|
||||
return c.Status(status).SendString(res)
|
||||
}
|
||||
|
||||
func HandleExplore(c *fiber.Ctx) error {
|
||||
defer calc(c.OriginalURL())()
|
||||
|
||||
@@ -48,11 +40,31 @@ func HandleNext(c *fiber.Ctx) error {
|
||||
return c.Status(status).SendString(res)
|
||||
}
|
||||
|
||||
func HandleGenres(c *fiber.Ctx) error {
|
||||
defer calc(c.OriginalURL())()
|
||||
|
||||
res, status := FetchGenres()
|
||||
|
||||
return c.Status(status).SendString(res)
|
||||
}
|
||||
|
||||
func HandleGenre(c *fiber.Ctx) error {
|
||||
defer calc(c.OriginalURL())()
|
||||
|
||||
res, status := FetchGenre(c.Params("id"))
|
||||
|
||||
return c.Status(status).SendString(res)
|
||||
}
|
||||
|
||||
func HandleBrowse(c *fiber.Ctx) error {
|
||||
defer calc(c.OriginalURL())()
|
||||
|
||||
id := c.Params("id")
|
||||
|
||||
if len(id) < 4 {
|
||||
return c.Status(500).SendString("{\"error\": \"Browse Id is too Short\"}")
|
||||
}
|
||||
|
||||
switch {
|
||||
case id[:2] == "UC":
|
||||
res, status := FetchArtist(id)
|
||||
@@ -63,11 +75,8 @@ func HandleBrowse(c *fiber.Ctx) error {
|
||||
case id[:4] == "MPRE":
|
||||
res, status := FetchAlbum(id)
|
||||
return c.Status(status).SendString(res)
|
||||
case id[:4] == "VLRD" || id[:2] == "RD":
|
||||
res, status := FetchPlaylist(id)
|
||||
return c.Status(status).SendString(res)
|
||||
default:
|
||||
return c.SendString("{\"error\": \"Invalid Browse URL\"}")
|
||||
return c.Status(500).SendString("{\"error\": \"Invalid Browse URL\"}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,9 +95,9 @@ func main() {
|
||||
app.Use(recover.New())
|
||||
|
||||
app.Get("/healthz", HandleHealth)
|
||||
app.Get("/home", HandleHome)
|
||||
app.Get("/home/:id", HandleHome)
|
||||
app.Get("/explore", HandleExplore)
|
||||
app.Get("/genres", HandleGenres)
|
||||
app.Get("/genres/:id", HandleGenre)
|
||||
app.Get("/next/:id", HandleNext)
|
||||
app.Get("/browse/:id", HandleBrowse)
|
||||
app.Get("/channel/:id", HandleArtist)
|
||||
|
||||
@@ -2,61 +2,11 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
func RunsText(j gjson.Result) string {
|
||||
|
||||
var s []string
|
||||
|
||||
a := j.Get("runs.#.text").Array()
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
s = append(s, a[i].String())
|
||||
}
|
||||
|
||||
return strings.Join(s, "")
|
||||
}
|
||||
|
||||
func GetThumbnails(j gjson.Result) []Thumbnail {
|
||||
|
||||
t := []Thumbnail{}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
j.ForEach(
|
||||
func(_, v gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
u, err := ParseUrl(v.Get("url").String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
t = append(t, Thumbnail{
|
||||
Url: u,
|
||||
Width: v.Get("width").Int(),
|
||||
Height: v.Get("height").Int(),
|
||||
})
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func GetNextSongs(n gjson.Result) []Item {
|
||||
|
||||
r := []Item{}
|
||||
@@ -88,47 +38,24 @@ func GetNextSongs(n gjson.Result) []Item {
|
||||
return r
|
||||
}
|
||||
|
||||
func ParseHome(raw string) (string, error) {
|
||||
func ParseExplore(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content.sectionListRenderer")
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content" +
|
||||
".tabRenderer.content.sectionListRenderer.contents.#.musicCarouselShelfRenderer")
|
||||
|
||||
m := c.Get("contents")
|
||||
n := c.Get("continuations.0.nextContinuationData.continuation").String()
|
||||
a := c.Get("#(header.musicCarouselShelfBasicHeaderRenderer" +
|
||||
".title.runs.0.text == New albums & singles)")
|
||||
t := c.Get("#(header.musicCarouselShelfBasicHeaderRenderer" +
|
||||
".title.runs.0.text == Trending)")
|
||||
|
||||
var body []map[string]interface{}
|
||||
|
||||
m.ForEach(
|
||||
func(key, value gjson.Result) bool {
|
||||
|
||||
var v map[string]interface{}
|
||||
|
||||
icsr := value.Get("musicImmersiveCarouselShelfRenderer")
|
||||
csr := value.Get("musicCarouselShelfRenderer")
|
||||
|
||||
switch {
|
||||
case icsr.Exists():
|
||||
v = CarouselShelfRenderer(icsr)
|
||||
case csr.Exists():
|
||||
v = CarouselShelfRenderer(csr)
|
||||
default:
|
||||
v = make(map[string]interface{})
|
||||
v["raw"] = value.Value()
|
||||
}
|
||||
|
||||
body = append(body, v)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
data := Home{
|
||||
Contents: body,
|
||||
Continue: n,
|
||||
val := Explore{
|
||||
Albums: TwoRowItemRenderer("album", a.Get("contents")),
|
||||
Trending: ResponsiveListItemRenderer(t.Get("contents")),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(data)
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -136,18 +63,45 @@ func ParseHome(raw string) (string, error) {
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func ParseExplore(raw string) (string, error) {
|
||||
func ParseGenres(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content.sectionListRenderer.contents")
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer" +
|
||||
".content.sectionListRenderer.contents.#.gridRenderer")
|
||||
|
||||
a := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == New albums & singles).musicCarouselShelfRenderer")
|
||||
t := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == Trending).musicCarouselShelfRenderer")
|
||||
m := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Moods & moments)")
|
||||
g := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Genres)")
|
||||
|
||||
val := Explore{
|
||||
Albums: TwoRowItemRenderer("album", a.Get("contents")),
|
||||
Trending: ResponsiveListItemRenderer(t.Get("contents")),
|
||||
val := Genres{
|
||||
Moods: NavigationButton(m.Get("items")),
|
||||
Genres: NavigationButton(g.Get("items")),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func ParseGenre(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer" +
|
||||
".content.sectionListRenderer.contents.#.gridRenderer")
|
||||
|
||||
s := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Spotlight)")
|
||||
f := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Featured playlists)")
|
||||
cp := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Community playlists)")
|
||||
|
||||
val := Genre{
|
||||
Title: RunsText(j.Get("header.musicHeaderRenderer.title")),
|
||||
Spotlight: TwoRowItemRenderer("", s.Get("items")),
|
||||
Featured: TwoRowItemRenderer("", f.Get("items")),
|
||||
Community: TwoRowItemRenderer("", cp.Get("items")),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
@@ -163,20 +117,29 @@ func ParseArtist(raw string) (string, error) {
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
h := j.Get("header.musicImmersiveHeaderRenderer")
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content.sectionListRenderer.contents")
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content" +
|
||||
".sectionListRenderer.contents")
|
||||
|
||||
s := c.Get("#(musicShelfRenderer.title.runs.0.text == Songs).musicShelfRenderer")
|
||||
a := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == Albums).musicCarouselShelfRenderer")
|
||||
m := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == Singles).musicCarouselShelfRenderer")
|
||||
u := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == Fans might also like).musicCarouselShelfRenderer")
|
||||
a := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer" +
|
||||
".title.runs.0.text == Albums).musicCarouselShelfRenderer")
|
||||
m := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer" +
|
||||
".title.runs.0.text == Singles).musicCarouselShelfRenderer")
|
||||
u := c.Get("#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer" +
|
||||
".title.runs.0.text == Fans might also like).musicCarouselShelfRenderer")
|
||||
|
||||
val := Artist{
|
||||
Title: RunsText(h.Get("title")),
|
||||
Description: RunsText(h.Get("description")),
|
||||
SubscriberCount: RunsText(h.Get("subscriptionButton.subscribeButtonRenderer.subscriberCountText")),
|
||||
Thumbnails: GetThumbnails(h.Get("thumbnail.musicThumbnailRenderer.thumbnail.thumbnails")),
|
||||
BrowsePlaylistId: h.Get("playButton.buttonRenderer.navigationEndpoint.watchEndpoint.playlistId").String(),
|
||||
PlaylistId: s.Get("contents.0.musicResponsiveListItemRenderer.flexColumns.0.musicResponsiveListItemFlexColumnRenderer.text.runs.0.navigationEndpoint.watchEndpoint.playlistId").String(),
|
||||
Title: RunsText(h.Get("title")),
|
||||
Description: RunsText(h.Get("description")),
|
||||
SubscriberCount: RunsText(h.Get("subscriptionButton" +
|
||||
".subscribeButtonRenderer.subscriberCountText")),
|
||||
Thumbnails: GetThumbnails(h.Get("thumbnail.musicThumbnailRenderer" +
|
||||
".thumbnail.thumbnails")),
|
||||
BrowsePlaylistId: h.Get("playButton.buttonRenderer.navigationEndpoint" +
|
||||
".watchEndpoint.playlistId").String(),
|
||||
PlaylistId: s.Get("contents.0.musicResponsiveListItemRenderer" +
|
||||
".flexColumns.0.musicResponsiveListItemFlexColumnRenderer.text" +
|
||||
".runs.0.navigationEndpoint.watchEndpoint.playlistId").String(),
|
||||
Items: Items{
|
||||
Songs: ResponsiveListItemRenderer(s.Get("contents")),
|
||||
Albums: TwoRowItemRenderer("album", a.Get("contents")),
|
||||
@@ -219,11 +182,15 @@ func ParseNext(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get("contents.singleColumnMusicWatchNextResultsRenderer.tabbedRenderer.watchNextTabbedResultsRenderer.tabs")
|
||||
m := j.Get("playerOverlays.playerOverlayRenderer.browserMediaSession.browserMediaSessionRenderer")
|
||||
c := j.Get("contents.singleColumnMusicWatchNextResultsRenderer." +
|
||||
"tabbedRenderer.watchNextTabbedResultsRenderer.tabs")
|
||||
m := j.Get("playerOverlays.playerOverlayRenderer.browserMediaSession" +
|
||||
".browserMediaSessionRenderer")
|
||||
|
||||
n := c.Get("#(tabRenderer.title == Up next).tabRenderer.content.musicQueueRenderer.content.playlistPanelRenderer")
|
||||
l := c.Get("#(tabRenderer.title == Lyrics).tabRenderer.endpoint.browseEndpoint.browseId")
|
||||
n := c.Get("#(tabRenderer.title == Up next).tabRenderer.content" +
|
||||
".musicQueueRenderer.content.playlistPanelRenderer")
|
||||
l := c.Get("#(tabRenderer.title == Lyrics).tabRenderer.endpoint" +
|
||||
".browseEndpoint.browseId")
|
||||
|
||||
val := Next{
|
||||
LyricsId: l.String(),
|
||||
|
||||
+36
-28
@@ -10,9 +10,9 @@ type Thumbnail struct {
|
||||
type Item struct {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Sub string `json:"subtitle"`
|
||||
SubId string `json:"subId"`
|
||||
Thumbnails []Thumbnail `json:"thumbnails"`
|
||||
Sub string `json:"subtitle,omitempty"`
|
||||
SubId string `json:"subId,omitempty"`
|
||||
Thumbnails []Thumbnail `json:"thumbnails,omitempty"`
|
||||
}
|
||||
|
||||
type Items struct {
|
||||
@@ -22,22 +22,29 @@ type Items struct {
|
||||
Artists []Item `json:"recommendedArtists"`
|
||||
}
|
||||
|
||||
type Home struct {
|
||||
Contents []map[string]interface{} `json:"contents"`
|
||||
Continue string `json:"continue"`
|
||||
}
|
||||
|
||||
type Explore struct {
|
||||
Albums []Item `json:"albums_and_singles"`
|
||||
Trending []Item `json:"trending"`
|
||||
}
|
||||
|
||||
type Genres struct {
|
||||
Moods []Item `json:"moods"`
|
||||
Genres []Item `json:"genres"`
|
||||
}
|
||||
|
||||
type Genre struct {
|
||||
Title string `json:"title"`
|
||||
Spotlight []Item `json:"spotlight"`
|
||||
Featured []Item `json:"featured"`
|
||||
Community []Item `json:"community"`
|
||||
}
|
||||
|
||||
type Artist struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
BrowsePlaylistId string `json:"browsePlaylistId"`
|
||||
PlaylistId string `json:"playlistId"`
|
||||
SubscriberCount string `json:"subscriberCount"`
|
||||
Description string `json:"description,omitempty"`
|
||||
BrowsePlaylistId string `json:"browsePlaylistId,omitempty"`
|
||||
PlaylistId string `json:"playlistId,omitempty"`
|
||||
SubscriberCount string `json:"subscriberCount,omitempty"`
|
||||
Thumbnails []Thumbnail `json:"thumbnails"`
|
||||
Items Items `json:"items"`
|
||||
}
|
||||
@@ -60,38 +67,39 @@ type Lyrics struct {
|
||||
|
||||
/* Structs and Types */
|
||||
type Client struct {
|
||||
Name string `json:"clientName"`
|
||||
Version string `json:"clientVersion"`
|
||||
Name string `json:"clientName,omitempty"`
|
||||
Version string `json:"clientVersion,omitempty"`
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
Client Client `json:"client"`
|
||||
Client Client `json:"client",omitempty`
|
||||
}
|
||||
|
||||
type PageType struct {
|
||||
PageType string `json:"pageType"`
|
||||
PageType string `json:"pageType",omitempty`
|
||||
}
|
||||
|
||||
type BrowseMusicConfig struct {
|
||||
MusicConfig PageType `json:"browseEndpointContextMusicConfig"`
|
||||
MusicConfig PageType `json:"browseEndpointContextMusicConfig,omitempty"`
|
||||
}
|
||||
|
||||
type WatchMusicConfig struct {
|
||||
Panel bool `json:"hasPersistentPlaylistPanel"`
|
||||
Type string `json:"musicVideoType"`
|
||||
Panel bool `json:"hasPersistentPlaylistPanel,omitempty"`
|
||||
Type string `json:"musicVideoType,omitempty"`
|
||||
}
|
||||
|
||||
type BrowseData struct {
|
||||
Context Context `json:"context"`
|
||||
MusicConfig BrowseMusicConfig `json:"browseEndpointContextMusicConfig"`
|
||||
BrowseId string `json:"browseId"`
|
||||
Context Context `json:"context,omitempty"`
|
||||
MusicConfig BrowseMusicConfig `json:"browseEndpointContextMusicConfig,omitempty"`
|
||||
BrowseId string `json:"browseId,omitempty"`
|
||||
Params string `json:"params,omitempty"`
|
||||
}
|
||||
|
||||
type NextData struct {
|
||||
Id string `json:"videoId"`
|
||||
Context Context `json:"context"`
|
||||
Audio bool `json:"isAudioOnly"`
|
||||
Tuner string `json:"tunerSettingValue"`
|
||||
Panel bool `json:"enablePersistentPlaylistPanel"`
|
||||
MusicConfig WatchMusicConfig `json:"watchEndpointMusicConfig"`
|
||||
Id string `json:"videoId,omitempty"`
|
||||
Context Context `json:"context,omitempty"`
|
||||
Audio bool `json:"isAudioOnly,omitempty"`
|
||||
Tuner string `json:"tunerSettingValue,omitempty"`
|
||||
Panel bool `json:"enablePersistentPlaylistPanel,omitempty"`
|
||||
MusicConfig WatchMusicConfig `json:"watchEndpointMusicConfig,omitempty"`
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ var BaseContext = Context{
|
||||
},
|
||||
}
|
||||
|
||||
func GetTypeBrowse(t, id string) BrowseData {
|
||||
func GetTypeBrowse(t, id string, params string) BrowseData {
|
||||
|
||||
if t != "" {
|
||||
return BrowseData{
|
||||
@@ -25,6 +25,7 @@ func GetTypeBrowse(t, id string) BrowseData {
|
||||
return BrowseData{
|
||||
Context: BaseContext,
|
||||
BrowseId: id,
|
||||
Params: params,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,25 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/tidwall/gjson"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RunsText(j gjson.Result) string {
|
||||
|
||||
var s []string
|
||||
|
||||
a := j.Get("runs.#.text").Array()
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
s = append(s, a[i].String())
|
||||
}
|
||||
|
||||
return strings.Join(s, "")
|
||||
}
|
||||
|
||||
func ParseUrl(raw string) (string, error) {
|
||||
|
||||
u, err := url.Parse(raw)
|
||||
@@ -24,7 +39,9 @@ func ParseUrl(raw string) (string, error) {
|
||||
}
|
||||
|
||||
func ErrorMessage(err error) string {
|
||||
return fmt.Sprintf("{\"error\": \"%s\", \"message\": \"Please Report this error\"}", err)
|
||||
data := url.QueryEscape(err.Error())
|
||||
fmt.Println(err)
|
||||
return fmt.Sprintf("{\"error\":\"%s\",\"message\":\"Got Error: %s\"}", data)
|
||||
}
|
||||
|
||||
func calc(url string) func() {
|
||||
|
||||
Reference in New Issue
Block a user