mirror of
https://codeberg.org/Hyperpipe/hyperpipe-backend
synced 2024-12-06 19:26:30 +01:00
Added 'next' endpoint and 'singles' for artist
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"bytes"
|
||||
"net/http"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func Fetch(data []byte) (string, int, error) {
|
||||
func Fetch(path string, data []byte) (string, int, error) {
|
||||
|
||||
url := "https://music.youtube.com/youtubei/v1/browse?key=AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30"
|
||||
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 {
|
||||
@@ -19,7 +19,8 @@ func Fetch(data []byte) (string, int, error) {
|
||||
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
req.Header.Set("Origin", "https://music.youtube.com")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)")
|
||||
req.Header.Set("x-origin", "https://music.youtube.com")
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36")
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
@@ -47,7 +48,7 @@ func FetchArtist(id string) (string, int) {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
raw, status, err := Fetch(data)
|
||||
raw, status, err := Fetch("browse", data)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
} else if status > 300 {
|
||||
@@ -59,5 +60,32 @@ func FetchArtist(id string) (string, int) {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
return res, 200
|
||||
return res, status
|
||||
}
|
||||
|
||||
func FetchNext(id string) (string, int) {
|
||||
|
||||
data, err := json.Marshal(GetTypeNext(id))
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
}
|
||||
|
||||
raw, status, err := Fetch("next", data)
|
||||
if err != nil {
|
||||
return ErrorMessage(err), 500
|
||||
} else if status > 300 {
|
||||
return raw, status
|
||||
}
|
||||
|
||||
res, err := ParseNext(raw)
|
||||
|
||||
return res, status
|
||||
}
|
||||
|
||||
/*func main() {
|
||||
|
||||
res, status := FetchNext("KWLGyeg74es")
|
||||
|
||||
log.Println(status)
|
||||
log.Println(res)
|
||||
}*/
|
||||
@@ -8,16 +8,25 @@ import (
|
||||
)
|
||||
|
||||
func SetHeaders(c *fiber.Ctx) error {
|
||||
c.Vary("Origin")
|
||||
c.Type("json", "utf-8")
|
||||
c.Set("Access-Control-Allow-Origin", "https://hyperpipe.surge.sh")
|
||||
c.Set("Access-Control-Allow-Origin", "*")
|
||||
c.Set("Access-Control-Allow-Headers", "*")
|
||||
c.Set("Access-Control-Max-Age", "1728000")
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
func HandleHealth(c *fiber.Ctx) error {
|
||||
defer calc()()
|
||||
|
||||
return c.Status(204).SendString("")
|
||||
return c.SendStatus(204)
|
||||
}
|
||||
|
||||
func HandleNext(c *fiber.Ctx) error {
|
||||
defer calc()()
|
||||
|
||||
res, status := FetchNext(c.Params("id"))
|
||||
return c.Status(status).SendString(res)
|
||||
}
|
||||
|
||||
func HandleBrowse(c *fiber.Ctx) error {
|
||||
@@ -47,6 +56,7 @@ func main() {
|
||||
app.Use(recover.New())
|
||||
|
||||
app.Get("/healthz", HandleHealth)
|
||||
app.Get("/next/:id", HandleNext)
|
||||
app.Get("/browse/:id", HandleBrowse)
|
||||
app.Get("/channel/:id", HandleArtist)
|
||||
|
||||
|
||||
@@ -72,11 +72,11 @@ func GetSongs(s gjson.Result) []Item {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("musicResponsiveListItemRenderer")
|
||||
f := 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: f.Get("#(navigationEndpoint.watchEndpoint.videoId).text").String(),
|
||||
Title: flex.Get("#(navigationEndpoint.watchEndpoint.videoId).text").String(),
|
||||
Thumbnails: GetThumbnails(j.Get("thumbnail.musicThumbnailRenderer.thumbnail.thumbnails")),
|
||||
})
|
||||
|
||||
@@ -97,9 +97,9 @@ func GetTwoRowItem(t string, a gjson.Result) []Item {
|
||||
|
||||
var id string
|
||||
|
||||
if t == "album" {
|
||||
if t == "album" || t == "singles" {
|
||||
id = "menu.menuRenderer.items.#(menuNavigationItemRenderer.text.runs.0.text == Shuffle play).menuNavigationItemRenderer.navigationEndpoint.watchPlaylistEndpoint.playlistId"
|
||||
} else if t == "artist" {
|
||||
} else {
|
||||
id = "navigationEndpoint.browseEndpoint.browseId"
|
||||
}
|
||||
|
||||
@@ -133,6 +133,39 @@ func GetTwoRowItem(t string, a gjson.Result) []Item {
|
||||
return r
|
||||
}
|
||||
|
||||
func GetNextSongs(n gjson.Result) []Item {
|
||||
|
||||
r := []Item{}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
n.ForEach(
|
||||
func(_, v gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("playlistPanelVideoRenderer")
|
||||
|
||||
r = append(r, Item{
|
||||
Id: j.Get("navigationEndpoint.watchEndpoint.videoId").String(),
|
||||
Title: RunsText(j.Get("title")),
|
||||
Sub: j.Get("longBylineText.runs.2.text").String(),
|
||||
Thumbnails: GetThumbnails(j.Get("thumbnail.thumbnails")),
|
||||
})
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func ParseArtist(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
@@ -142,6 +175,7 @@ func ParseArtist(raw string) (string, error) {
|
||||
|
||||
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")
|
||||
|
||||
val := Artist{
|
||||
@@ -154,6 +188,7 @@ func ParseArtist(raw string) (string, error) {
|
||||
Items: Items{
|
||||
Songs: GetSongs(s.Get("contents")),
|
||||
Albums: GetTwoRowItem("album", a.Get("contents")),
|
||||
Singles: GetTwoRowItem("singles", m.Get("contents")),
|
||||
Artists: GetTwoRowItem("artist", u.Get("contents")),
|
||||
},
|
||||
}
|
||||
@@ -165,3 +200,26 @@ func ParseArtist(raw string) (string, error) {
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func ParseNext(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
m := j.Get("playerOverlays.playerOverlayRenderer.browserMediaSession.browserMediaSessionRenderer")
|
||||
n := j.Get("contents.singleColumnMusicWatchNextResultsRenderer.tabbedRenderer.watchNextTabbedResultsRenderer.tabs.#(tabRenderer.title == Up next).tabRenderer.content.musicQueueRenderer.content.playlistPanelRenderer")
|
||||
|
||||
val := Next{
|
||||
MediaSession: MediaSession{
|
||||
Album: RunsText(m.Get("album")),
|
||||
Thumbnails: GetThumbnails(m.Get("thumbnailDetails.thumbnails")),
|
||||
},
|
||||
Songs: GetNextSongs(n.Get("contents")),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
+34
-5
@@ -1,5 +1,7 @@
|
||||
package main
|
||||
|
||||
|
||||
/* Parsers */
|
||||
type Thumbnail struct {
|
||||
Height int64 `json:"height"`
|
||||
Width int64 `json:"width"`
|
||||
@@ -16,6 +18,7 @@ type Item struct {
|
||||
type Items struct {
|
||||
Songs []Item `json:"songs"`
|
||||
Albums []Item `json:"albums"`
|
||||
Singles []Item `json:"singles"`
|
||||
Artists []Item `json:"recommendedArtists"`
|
||||
}
|
||||
|
||||
@@ -29,6 +32,18 @@ type Artist struct {
|
||||
Items Items `json:"items"`
|
||||
}
|
||||
|
||||
type MediaSession struct {
|
||||
Thumbnails []Thumbnail `json:"thumbnails"`
|
||||
Album string `json:"album"`
|
||||
}
|
||||
|
||||
type Next struct {
|
||||
Songs []Item `json:"songs"`
|
||||
MediaSession MediaSession `json:"mediaSession"`
|
||||
}
|
||||
|
||||
|
||||
/* Structs and Types */
|
||||
type Client struct {
|
||||
Name string `json:"clientName"`
|
||||
Version string `json:"clientVersion"`
|
||||
@@ -42,12 +57,26 @@ type PageType struct {
|
||||
PageType string `json:"pageType"`
|
||||
}
|
||||
|
||||
type MusicConfig struct {
|
||||
type BrowseMusicConfig struct {
|
||||
MusicConfig PageType `json:"browseEndpointContextMusicConfig"`
|
||||
}
|
||||
|
||||
type BrowseData struct {
|
||||
Context Context `json:"context"`
|
||||
MusicConfig MusicConfig `json:"browseEndpointContextMusicConfig"`
|
||||
BrowseId string `json:"browseId"`
|
||||
type WatchMusicConfig struct {
|
||||
Panel bool `json:"hasPersistentPlaylistPanel"`
|
||||
Type string `json:"musicVideoType"`
|
||||
}
|
||||
|
||||
type BrowseData struct {
|
||||
Context Context `json:"context"`
|
||||
MusicConfig BrowseMusicConfig `json:"browseEndpointContextMusicConfig"`
|
||||
BrowseId string `json:"browseId"`
|
||||
}
|
||||
|
||||
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"`
|
||||
}
|
||||
|
||||
@@ -2,19 +2,17 @@ package main
|
||||
|
||||
import "strings"
|
||||
|
||||
func GetContext() Context {
|
||||
return Context{
|
||||
Client: Client{
|
||||
Name: "WEB_REMIX",
|
||||
Version: "1.20211213.00.00",
|
||||
},
|
||||
}
|
||||
var BaseContext = Context{
|
||||
Client: Client{
|
||||
Name: "WEB_REMIX",
|
||||
Version: "1.20211213.00.00",
|
||||
},
|
||||
}
|
||||
|
||||
func GetTypeBrowse(t, id string) BrowseData {
|
||||
return BrowseData{
|
||||
Context: GetContext(),
|
||||
MusicConfig: MusicConfig{
|
||||
Context: BaseContext,
|
||||
MusicConfig: BrowseMusicConfig{
|
||||
MusicConfig: PageType{
|
||||
PageType: "MUSIC_PAGE_TYPE_" + strings.ToUpper(t),
|
||||
},
|
||||
@@ -22,3 +20,17 @@ func GetTypeBrowse(t, id string) BrowseData {
|
||||
BrowseId: id,
|
||||
}
|
||||
}
|
||||
|
||||
func GetTypeNext(id string) NextData {
|
||||
return NextData{
|
||||
Id: id,
|
||||
Context: BaseContext,
|
||||
Panel: true,
|
||||
Audio: true,
|
||||
Tuner: "AUTOMIX_SETTING_NORMAL",
|
||||
MusicConfig: WatchMusicConfig{
|
||||
Panel: true,
|
||||
Type: "MUSIC_VIDEO_TYPE_ATV",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user