mirror of
https://codeberg.org/Hyperpipe/hyperpipe-backend
synced 2024-12-06 19:26:30 +01:00
Changes:
- Proper structure for code - Support for musicCarouselShelfRenderer in genres
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Artist struct {
|
||||
Title string `json:"title"`
|
||||
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"`
|
||||
}
|
||||
|
||||
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",
|
||||
)
|
||||
|
||||
s := c.Get("#(musicShelfRenderer.title.runs.0.text == Songs).musicShelfRenderer")
|
||||
|
||||
a := c.Get(
|
||||
"#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer",
|
||||
).Get("title.runs.0.text == Albums).musicCarouselShelfRenderer")
|
||||
|
||||
m := c.Get(
|
||||
"#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer",
|
||||
).Get("title.runs.0.text == Singles).musicCarouselShelfRenderer")
|
||||
|
||||
u := c.Get(
|
||||
"#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer",
|
||||
).Get("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",
|
||||
).Get("text.runs.0.navigationEndpoint.watchEndpoint.playlistId").String(),
|
||||
Items: Items{
|
||||
Songs: ResponsiveListItemRenderer(s.Get("contents")),
|
||||
Albums: TwoRowItemRenderer(a.Get("contents"), true),
|
||||
Singles: TwoRowItemRenderer(m.Get("contents"), true),
|
||||
Artists: TwoRowItemRenderer(u.Get("contents"), false),
|
||||
},
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func GetArtist(id string) (string, int) {
|
||||
|
||||
context := utils.TypeBrowse("artist", id, "", "")
|
||||
|
||||
raw, status := utils.FetchBrowse(context)
|
||||
|
||||
res, err := parseArtist(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Default string `json:"default"`
|
||||
All []Item `json:"all"`
|
||||
}
|
||||
|
||||
type Charts struct {
|
||||
Options Options `json:"options"`
|
||||
Artists []Item `json:"artists"`
|
||||
Trending []Item `json:"trending"`
|
||||
}
|
||||
|
||||
func parseCharts(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0").Get("tabRenderer.content.sectionListRenderer.contents")
|
||||
|
||||
o := c.Get(
|
||||
"0.musicShelfRenderer.subheaders.0.musicSideAlignedItemRenderer",
|
||||
).Get(
|
||||
"startItems.0.musicSortFilterButtonRenderer",
|
||||
)
|
||||
|
||||
a := c.Get(
|
||||
"#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer",
|
||||
).Get(
|
||||
"title.runs.0.text == Top artists).musicCarouselShelfRenderer.contents",
|
||||
)
|
||||
|
||||
t := c.Get(
|
||||
"#(musicCarouselShelfRenderer.header.musicCarouselShelfBasicHeaderRenderer",
|
||||
).Get("title.runs.0.text == Trending).musicCarouselShelfRenderer.contents")
|
||||
|
||||
opts := o.Get(
|
||||
"menu.musicMultiSelectMenuRenderer.options.#.musicMultiSelectMenuItemRenderer",
|
||||
)
|
||||
ref := j.Get("frameworkUpdates.entityBatchUpdate.mutations")
|
||||
|
||||
val := Charts{
|
||||
Options: Options{
|
||||
Default: RunsText(o.Get("title")),
|
||||
All: MultiSelectMenuItemRenderer(opts, ref),
|
||||
},
|
||||
Artists: ResponsiveListItemRendererCH(a),
|
||||
Trending: ResponsiveListItemRenderer(t),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func GetCharts(params, code string) (string, int) {
|
||||
|
||||
context := utils.TypeBrowse("", "FEmusic_charts", params, code)
|
||||
|
||||
raw, status := utils.FetchBrowse(context)
|
||||
|
||||
res, err := parseCharts(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Thumbnail struct {
|
||||
Height int64 `json:"height"`
|
||||
Width int64 `json:"width"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Sub string `json:"subtitle,omitempty"`
|
||||
SubId string `json:"subId,omitempty"`
|
||||
Thumbnails []Thumbnail `json:"thumbnails,omitempty"`
|
||||
}
|
||||
|
||||
type Items struct {
|
||||
Songs []Item `json:"songs"`
|
||||
Albums []Item `json:"albums"`
|
||||
Singles []Item `json:"singles"`
|
||||
Artists []Item `json:"recommendedArtists"`
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
prehost := u.Host
|
||||
|
||||
u.Scheme = "https"
|
||||
u.Host = os.Getenv("HYP_PROXY")
|
||||
|
||||
q := u.Query()
|
||||
q.Set("host", prehost)
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func GetThumbnails(j gjson.Result) []Thumbnail {
|
||||
|
||||
t := make([]Thumbnail, j.Get("#").Int())
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
j.ForEach(
|
||||
func(n, j gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, v gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
u, err := parseUrl(v.Get("url").String())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
t[i] = Thumbnail{
|
||||
Url: u,
|
||||
Width: v.Get("width").Int(),
|
||||
Height: v.Get("height").Int(),
|
||||
}
|
||||
}(n.Int(), j)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func TwoRowItemRenderer(a gjson.Result, t bool) []Item {
|
||||
|
||||
var id string
|
||||
|
||||
if t {
|
||||
id = "menu.menuRenderer.items.#(menuNavigationItemRenderer.text.runs.0.text == Shuffle play).menuNavigationItemRenderer.navigationEndpoint.watchPlaylistEndpoint.playlistId"
|
||||
} else {
|
||||
id = "navigationEndpoint.browseEndpoint.browseId"
|
||||
}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
v := a.Get("#.musicTwoRowItemRenderer")
|
||||
|
||||
r := make([]Item, v.Get("#").Int())
|
||||
|
||||
v.ForEach(
|
||||
func(n, s gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, j gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
gid := j.Get(id).String()
|
||||
|
||||
if len(gid) > 2 && gid[:2] == "VL" {
|
||||
gid = gid[2:]
|
||||
}
|
||||
|
||||
r[i] = Item{
|
||||
Id: gid,
|
||||
Title: RunsText(j.Get("title")),
|
||||
Sub: RunsText(j.Get("subtitle")),
|
||||
Thumbnails: GetThumbnails(
|
||||
j.Get("thumbnailRenderer.musicThumbnailRenderer.thumbnail.thumbnails"),
|
||||
),
|
||||
}
|
||||
|
||||
}(n.Int(), s)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func ResponsiveListItemRenderer(s gjson.Result) []Item {
|
||||
|
||||
r := make([]Item, s.Get("#").Int())
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
s.ForEach(
|
||||
func(n, s gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, v gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("musicResponsiveListItemRenderer")
|
||||
flex := j.Get("flexColumns.#.musicResponsiveListItemFlexColumnRenderer" +
|
||||
".text.runs.0")
|
||||
|
||||
r[i] = Item{
|
||||
Id: j.Get("playlistItemData.videoId").String(),
|
||||
Title: flex.Get("#(navigationEndpoint.watchEndpoint.videoId).text").String(),
|
||||
SubId: flex.Get(
|
||||
"#.navigationEndpoint.browseEndpoint.browseId.0",
|
||||
).String(),
|
||||
Sub: flex.Get(
|
||||
"#(navigationEndpoint.browseEndpoint.browseId).text",
|
||||
).String(),
|
||||
Thumbnails: GetThumbnails(
|
||||
j.Get("thumbnail.musicThumbnailRenderer.thumbnail.thumbnails"),
|
||||
),
|
||||
}
|
||||
|
||||
}(n.Int(), s)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func ResponsiveListItemRendererCH(s gjson.Result) []Item {
|
||||
|
||||
r := make([]Item, s.Get("#").Int())
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
s.ForEach(
|
||||
func(n, s gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, v gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("musicResponsiveListItemRenderer")
|
||||
flex := j.Get("flexColumns.#.musicResponsiveListItemFlexColumnRenderer" +
|
||||
".text.runs.0.text")
|
||||
|
||||
r[i] = Item{
|
||||
Id: j.Get("navigationEndpoint.browseEndpoint.browseId").String(),
|
||||
Title: flex.Get("0").String() + " • " + flex.Get("1").String(),
|
||||
Thumbnails: GetThumbnails(
|
||||
j.Get("thumbnail.musicThumbnailRenderer.thumbnail.thumbnails"),
|
||||
),
|
||||
}
|
||||
|
||||
}(n.Int(), s)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func NavigationButton(s gjson.Result) []Item {
|
||||
|
||||
r := make([]Item, s.Get("#").Int())
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
s.ForEach(
|
||||
func(n, s gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, v gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
j := v.Get("musicNavigationButtonRenderer")
|
||||
|
||||
color := j.Get("solid.leftStripeColor").Uint() & 0xffffff
|
||||
|
||||
r[i] = Item{
|
||||
Id: j.Get("clickCommand.browseEndpoint.params").String(),
|
||||
Title: RunsText(j.Get("buttonText")),
|
||||
Sub: fmt.Sprintf("#%06x", color),
|
||||
}
|
||||
}(n.Int(), s)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func MultiSelectMenuItemRenderer(j, ref gjson.Result) []Item {
|
||||
|
||||
r := make([]Item, j.Get("#").Int())
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
j.ForEach(
|
||||
func(n, s gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, v gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
steg := v.Get("formItemEntityKey").String()
|
||||
|
||||
id := ref.Get(
|
||||
"#(entityKey == " + steg + ")",
|
||||
).Get(".payload.musicFormBooleanChoice.opaqueToken")
|
||||
|
||||
r[i] = Item{
|
||||
Id: id.String(),
|
||||
Title: RunsText(v.Get("title")),
|
||||
}
|
||||
}(n.Int(), s)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func ShelfRenderer(j gjson.Result) map[string]interface{} {
|
||||
|
||||
r := make(map[string]interface{})
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
j.ForEach(
|
||||
func(n, s gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(v gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
title := RunsText(
|
||||
v.Get("header.musicCarouselShelfBasicHeaderRenderer.title"),
|
||||
)
|
||||
|
||||
r[title] = TwoRowItemRenderer(v.Get("contents"), false)
|
||||
}(s)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Explore struct {
|
||||
TrendingId string `json:"trendingId"`
|
||||
ChartsId string `json:"chartsId"`
|
||||
Albums []Item `json:"albums_and_singles"`
|
||||
Trending []Item `json:"trending"`
|
||||
}
|
||||
|
||||
func parseExplore(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
m := j.Get(
|
||||
"contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content.sectionListRenderer.contents",
|
||||
)
|
||||
|
||||
c := m.Get("#.musicCarouselShelfRenderer")
|
||||
|
||||
a := c.Get(
|
||||
"#(header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == New albums & singles)",
|
||||
)
|
||||
t := c.Get("#(header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.text == Trending)")
|
||||
|
||||
charts := m.Get(
|
||||
"#(gridRenderer).gridRenderer.items.#.musicNavigationButtonRenderer",
|
||||
).Get("#(buttonText.runs.0.text == Charts)")
|
||||
|
||||
val := Explore{
|
||||
TrendingId: t.Get(
|
||||
"header.musicCarouselShelfBasicHeaderRenderer.title.runs.0.navigationEndpoint.browseEndpoint.browseId",
|
||||
).String(),
|
||||
ChartsId: charts.Get("clickCommand.browseEndpoint.params").String(),
|
||||
Albums: TwoRowItemRenderer(a.Get("contents"), true),
|
||||
Trending: ResponsiveListItemRenderer(t.Get("contents")),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func GetExplore() (string, int) {
|
||||
|
||||
context := utils.TypeBrowse("", "FEmusic_explore", "", "")
|
||||
|
||||
raw, status := utils.FetchBrowse(context)
|
||||
|
||||
res, err := parseExplore(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Genre struct {
|
||||
Title string `json:"title"`
|
||||
Spotlight []Item `json:"spotlight"`
|
||||
Featured []Item `json:"featured"`
|
||||
Community []Item `json:"community"`
|
||||
Shelf map[string]interface{} `json:"shelf"`
|
||||
}
|
||||
|
||||
func parseGenre(raw string) (string, error) {
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get(
|
||||
"contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer.content.sectionListRenderer.contents",
|
||||
)
|
||||
|
||||
g := c.Get("#.gridRenderer")
|
||||
|
||||
var val Genre
|
||||
|
||||
s := g.Get("#(header.gridHeaderRenderer.title.runs.0.text == Spotlight)")
|
||||
f := g.Get("#(header.gridHeaderRenderer.title.runs.0.text == Featured playlists)")
|
||||
cp := g.Get("#(header.gridHeaderRenderer.title.runs.0.text == Community playlists)")
|
||||
|
||||
val = Genre{
|
||||
Title: RunsText(j.Get("header.musicHeaderRenderer.title")),
|
||||
Spotlight: TwoRowItemRenderer(s.Get("items"), false),
|
||||
Featured: TwoRowItemRenderer(f.Get("items"), false),
|
||||
Community: TwoRowItemRenderer(cp.Get("items"), false),
|
||||
Shelf: ShelfRenderer(
|
||||
c.Get("#.musicCarouselShelfRenderer"),
|
||||
),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func GetGenre(param string) (string, int) {
|
||||
|
||||
context := utils.TypeBrowse("", "FEmusic_moods_and_genres_category", param, "")
|
||||
|
||||
raw, status := utils.FetchBrowse(context)
|
||||
|
||||
res, err := parseGenre(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Genres struct {
|
||||
Moods []Item `json:"moods"`
|
||||
Genres []Item `json:"genres"`
|
||||
}
|
||||
|
||||
func parseGenres(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
c := j.Get("contents.singleColumnBrowseResultsRenderer.tabs.0.tabRenderer" +
|
||||
".content.sectionListRenderer.contents.#.gridRenderer")
|
||||
|
||||
m := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Moods & moments)")
|
||||
g := c.Get("#(header.gridHeaderRenderer.title.runs.0.text == Genres)")
|
||||
|
||||
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 GetGenres() (string, int) {
|
||||
|
||||
context := utils.TypeBrowse("", "FEmusic_moods_and_genres", "", "")
|
||||
|
||||
raw, status := utils.FetchBrowse(context)
|
||||
|
||||
res, err := parseGenres(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type Lyrics struct {
|
||||
Text string `json:"text"`
|
||||
Source string `json:"source"`
|
||||
}
|
||||
|
||||
func parseLyrics(raw string) (string, error) {
|
||||
|
||||
j := gjson.Parse(raw)
|
||||
|
||||
d := j.Get("contents.sectionListRenderer.contents.0.musicDescriptionShelfRenderer")
|
||||
|
||||
l := d.Get("description")
|
||||
s := d.Get("footer")
|
||||
|
||||
val := Lyrics{
|
||||
Text: RunsText(l),
|
||||
Source: RunsText(s),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func GetLyrics(id string) (string, int) {
|
||||
|
||||
context := utils.TypeBrowse("lyrics", id, "", "")
|
||||
|
||||
raw, status := utils.FetchBrowse(context)
|
||||
|
||||
res, err := parseLyrics(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"codeberg.org/Hyperpipe/hyperpipe-backend/utils"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type MediaSession struct {
|
||||
Thumbnails []Thumbnail `json:"thumbnails"`
|
||||
Album string `json:"album"`
|
||||
}
|
||||
|
||||
type Next struct {
|
||||
LyricsId string `json:"lyricsId"`
|
||||
Songs []Item `json:"songs"`
|
||||
MediaSession MediaSession `json:"mediaSession"`
|
||||
}
|
||||
|
||||
func parseNextSongs(n gjson.Result) []Item {
|
||||
|
||||
np := n.Get("#.playlistPanelVideoRenderer")
|
||||
|
||||
r := make([]Item, n.Get("#").Int())
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
np.ForEach(
|
||||
func(n, v gjson.Result) bool {
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go func(i int64, j gjson.Result) {
|
||||
defer wg.Done()
|
||||
|
||||
r[i] = 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")),
|
||||
}
|
||||
}(n.Int(), v)
|
||||
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
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",
|
||||
)
|
||||
|
||||
n := c.Get(
|
||||
"#(tabRenderer.title == Up next).tabRenderer.content",
|
||||
).Get("musicQueueRenderer.content.playlistPanelRenderer")
|
||||
|
||||
l := c.Get(
|
||||
"#(tabRenderer.title == Lyrics).tabRenderer.endpoint.browseEndpoint.browseId",
|
||||
)
|
||||
|
||||
val := Next{
|
||||
LyricsId: l.String(),
|
||||
MediaSession: MediaSession{
|
||||
Album: RunsText(m.Get("album")),
|
||||
Thumbnails: GetThumbnails(m.Get("thumbnailDetails.thumbnails")),
|
||||
},
|
||||
Songs: parseNextSongs(n.Get("contents")),
|
||||
}
|
||||
|
||||
res, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(res), nil
|
||||
}
|
||||
|
||||
func GetNext(id string) (string, int) {
|
||||
|
||||
pldata, err := json.Marshal(utils.TypeNext(id, ""))
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
plraw, plstatus, err := utils.Fetch("next", pldata)
|
||||
if err != nil || plstatus > 399 {
|
||||
return utils.ErrMsg(err), plstatus
|
||||
}
|
||||
|
||||
pl := gjson.Parse(plraw).Get(
|
||||
"contents.singleColumnMusicWatchNextResultsRenderer." +
|
||||
"tabbedRenderer.watchNextTabbedResultsRenderer.tabs.0.tabRenderer.content." +
|
||||
"musicQueueRenderer.content.playlistPanelRenderer.contents." +
|
||||
"#(automixPreviewVideoRenderer).automixPreviewVideoRenderer." +
|
||||
"content.automixPlaylistVideoRenderer.navigationEndpoint." +
|
||||
"watchPlaylistEndpoint.playlistId").String()
|
||||
|
||||
data, err := json.Marshal(utils.TypeNext(id, pl))
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
raw, status, err := utils.Fetch("next", data)
|
||||
|
||||
res, err := parseNext(raw)
|
||||
if err != nil {
|
||||
return utils.ErrMsg(err), 500
|
||||
}
|
||||
|
||||
return res, status
|
||||
}
|
||||
Reference in New Issue
Block a user