fix skill issues w/ restream

This commit is contained in:
Laptop
2025-06-21 12:34:45 +03:00
parent 5e96cee22e
commit cf369e3f28
4 changed files with 43 additions and 47 deletions

View File

@@ -70,7 +70,7 @@ func Load(r *fiber.App) {
return err return err
} }
c.Request().Header.SetContentType(tr.Format.MimeType) c.Response().Header.SetContentType(tr.Format.MimeType)
c.Set("Cache-Control", cfg.RestreamCacheControl) c.Set("Cache-Control", cfg.RestreamCacheControl)
if isDownload { if isDownload {
@@ -99,23 +99,23 @@ func Load(r *fiber.App) {
r.req.SetRequestURI(t.Artwork) r.req.SetRequestURI(t.Artwork)
err := sc.DoWithRetry(misc.ImageClient, r.req, r.resp) err := sc.DoWithRetry(misc.ImageClient, r.req, r.resp)
if err != nil { if err == nil && r.resp.StatusCode() == 200 {
return err tag.AddAttachedPicture(id3v2.PictureFrame{MimeType: cfg.B2s(r.req.Header.ContentType()), Picture: r.req.Body(), PictureType: id3v2.PTFrontCover, Encoding: id3v2.EncodingUTF8})
} }
tag.AddAttachedPicture(id3v2.PictureFrame{MimeType: cfg.B2s(r.req.Header.ContentType()), Picture: r.req.Body(), PictureType: id3v2.PTFrontCover, Encoding: id3v2.EncodingUTF8})
} }
var col collector var col collector
tag.WriteTo(&col) tag.WriteTo(&col)
r.leftover = col.data r.leftover = col.data
c.Response().Header.SetContentType("audio/mpeg")
return c.SendStream(r) return c.SendStream(r)
case cfg.AudioOpus: // might try to fuck around with metadata injection. Dynamically injecting metadata for opus wasn't really good idea as it breaks some things :P case cfg.AudioOpus: // might try to fuck around with metadata injection. Dynamically injecting metadata for opus wasn't really good idea as it breaks some things :P
req := fasthttp.AcquireRequest() req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse() resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)
req.SetRequestURI(u) req.SetRequestURI(u)
req.Header.SetUserAgent(cfg.UserAgent) req.Header.SetUserAgent(cfg.UserAgent)
@@ -124,23 +124,24 @@ func Load(r *fiber.App) {
return err return err
} }
data := resp.Body() parts := make([][]byte, 0, defaultPartsCapacity)
for _, s := range bytes.Split(resp.Body(), newline) {
res := make([]byte, 0, 1024*1024*1)
for _, s := range bytes.Split(data, []byte{'\n'}) {
if len(s) == 0 || s[0] == '#' { if len(s) == 0 || s[0] == '#' {
continue continue
} }
parts = append(parts, clone(s))
}
res := make([]byte, 0, 1024*1024*1)
for _, s := range parts {
req.SetRequestURIBytes(s) req.SetRequestURIBytes(s)
err := sc.DoWithRetry(misc.HlsClient, req, resp) err := sc.DoWithRetry(misc.HlsClient, req, resp)
if err != nil { if err != nil {
return err return err
} }
data = resp.Body() res = append(res, resp.Body()...)
res = append(res, data...)
} }
tag, err := oggmeta.ReadOGG(bytes.NewReader(res)) tag, err := oggmeta.ReadOGG(bytes.NewReader(res))
@@ -159,24 +160,18 @@ func Load(r *fiber.App) {
req.SetRequestURI(t.Artwork) req.SetRequestURI(t.Artwork)
err := sc.DoWithRetry(misc.ImageClient, req, resp) err := sc.DoWithRetry(misc.ImageClient, req, resp)
if err != nil { if err == nil && resp.StatusCode() == 200 {
return err parsed, _, err := image.Decode(resp.BodyStream())
if err == nil {
tag.SetCoverArt(&parsed)
}
} }
parsed, _, err := image.Decode(resp.BodyStream())
resp.CloseBodyStream()
if err != nil {
return err
}
tag.SetCoverArt(&parsed)
} }
c.Response().Header.SetContentType(`audio/ogg; codecs="opus"`)
return tag.Save(c.Response().BodyWriter()) return tag.Save(c.Response().BodyWriter())
case cfg.AudioAAC: case cfg.AudioAAC:
r := acquireReader() r := acquireReader()
err := r.Setup(u, true, &t.Duration) err := r.Setup(u, true, nil)
if err != nil { if err != nil {
return err return err
} }
@@ -204,17 +199,13 @@ func Load(r *fiber.App) {
r.req.SetRequestURI(t.Artwork) r.req.SetRequestURI(t.Artwork)
err := sc.DoWithRetry(misc.ImageClient, r.req, r.resp) err := sc.DoWithRetry(misc.ImageClient, r.req, r.resp)
if err != nil { if err == nil && r.resp.StatusCode() == 200 {
return err parsed, _, err := image.Decode(r.resp.BodyStream())
r.resp.CloseBodyStream()
if err == nil {
tag.SetCoverArt(&parsed)
}
} }
parsed, _, err := image.Decode(r.resp.BodyStream())
r.resp.CloseBodyStream()
if err != nil {
return err
}
tag.SetCoverArt(&parsed)
} }
var col collector var col collector
@@ -222,7 +213,6 @@ func Load(r *fiber.App) {
fixDuration(col.data, &t.Duration) fixDuration(col.data, &t.Duration)
r.leftover = col.data r.leftover = col.data
c.Response().Header.SetContentType("audio/mp4")
return c.SendStream(r) return c.SendStream(r)
} }
} }

View File

@@ -42,6 +42,7 @@ func clone(buf []byte) []byte {
} }
var mvhd = []byte("mvhd") var mvhd = []byte("mvhd")
var newline = []byte{'\n'}
func fixDuration(data []byte, duration *uint32) { func fixDuration(data []byte, duration *uint32) {
i := bytes.Index(data, mvhd) i := bytes.Index(data, mvhd)
@@ -85,9 +86,9 @@ func (r *reader) Setup(url string, aac bool, duration *uint32) error {
} else { } else {
misc.Log(cap(r.parts), len(r.parts)) misc.Log(cap(r.parts), len(r.parts))
} }
// clone needed to mitigate memory skill issues smh
if aac { if aac {
// clone needed to mitigate memory skill issues here for _, s := range bytes.Split(r.resp.Body(), newline) {
for _, s := range bytes.Split(r.resp.Body(), []byte{'\n'}) {
if len(s) == 0 { if len(s) == 0 {
continue continue
} }
@@ -102,12 +103,12 @@ func (r *reader) Setup(url string, aac bool, duration *uint32) error {
r.parts = append(r.parts, clone(s)) r.parts = append(r.parts, clone(s))
} }
} else { } else {
for _, s := range bytes.Split(r.resp.Body(), []byte{'\n'}) { for _, s := range bytes.Split(r.resp.Body(), newline) {
if len(s) == 0 || s[0] == '#' { if len(s) == 0 || s[0] == '#' {
continue continue
} }
r.parts = append(r.parts, s) r.parts = append(r.parts, clone(s))
} }
} }
@@ -127,7 +128,7 @@ func (r *reader) Close() error {
return nil return nil
} }
// you could prob make this a bit faster by concurrency (make a bunch of workers => make them download the parts => temporarily add them to a map => fully assemble the result => make reader.Read() read out the result as the parts are coming in) but whatever, fine for now // I have no idea what this truly even does anymore. Maybe a rewrite/refactor would be good?
func (r *reader) Read(buf []byte) (n int, err error) { func (r *reader) Read(buf []byte) (n int, err error) {
misc.Log("we read") misc.Log("we read")
if len(r.leftover) != 0 { if len(r.leftover) != 0 {

View File

@@ -50,16 +50,20 @@ type Track struct {
type TrackPolicy string type TrackPolicy string
const ( const (
PolicyBlock TrackPolicy = "BLOCK" // not available (in your country) PolicyMonetize TrackPolicy = "MONETIZE" // seems like only certain countries get this policy? sometimes protected by widevine and fairplay
PolicySnip TrackPolicy = "SNIP" // 30-second snippet available PolicyBlock TrackPolicy = "BLOCK" // not available (in your country)
PolicyAllow TrackPolicy = "ALLOW" // all good PolicySnip TrackPolicy = "SNIP" // 30-second snippet available
PolicyAllow TrackPolicy = "ALLOW" // all good
) )
type Protocol string type Protocol string
const ( const (
ProtocolHLS Protocol = "hls" ProtocolHLS Protocol = "hls"
ProtocolProgressive Protocol = "progressive" ProtocolProgressive Protocol = "progressive"
ProtocolEncryptedHLS Protocol = "encrypted-hls" // idk, haven't seen in the wild
ProtocolCTREncryptedHLS Protocol = "ctr-encrypted-hls" // google's widevine
ProtocolCBCEncryptedHLS Protocol = "cbc-encrypted-hls" // apple's fairplay
) )
type Format struct { type Format struct {

View File

@@ -171,7 +171,7 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string,
} }
<h1>{ t.Title }</h1> <h1>{ t.Title }</h1>
@TrackPlayer(prefs, t, stream, displayErr, autoplay, nextTrack, playlist, volume, mode, audio) @TrackPlayer(prefs, t, stream, displayErr, autoplay, nextTrack, playlist, volume, mode, audio)
if cfg.Restream { if displayErr == "" && cfg.Restream {
<div style="display: flex; margin-bottom: 1rem;"> <div style="display: flex; margin-bottom: 1rem;">
<a class="btn" href={ templ.SafeURL("/_/restream" + t.Href() + "?metadata=true") } download={ t.Permalink + "." + toExt(*downloadAudio) }>download</a> <a class="btn" href={ templ.SafeURL("/_/restream" + t.Href() + "?metadata=true") } download={ t.Permalink + "." + toExt(*downloadAudio) }>download</a>
</div> </div>
@@ -220,6 +220,7 @@ templ Track(prefs cfg.Preferences, t sc.Track, stream string, displayErr string,
if t.License != "" { if t.License != "" {
<p>License: { t.License }</p> <p>License: { t.License }</p>
} }
<p>Policy: { t.Policy }</p>
if t.TagList != "" { if t.TagList != "" {
<p>Tags: { strings.Join(sc.TagListParser(t.TagList), ", ") }</p> <p>Tags: { strings.Join(sc.TagListParser(t.TagList), ", ") }</p>
} }