initial commit

This commit is contained in:
Wouter Groeneveld 2023-02-09 12:40:56 +01:00
parent b7797b30f6
commit bd34f9f36f
5 changed files with 112 additions and 1 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.idea/
_rest_stream*
.DS_Store

View File

@ -1,3 +1,15 @@
<<<<<<< HEAD
# subfmproxy
A Subsonic FM Transmitter Proxy: Stream your music to your retro radios!
A Subsonic FM Transmitter Proxy: Stream your music to your retro radios!
=======
## Inspiration
- https://github.com/dlsniper/fmradio and talk https://www.youtube.com/watch?v=o5MTRQmhvCk
- (with device https://www.adafruit.com/product/1958)
- with GoBot to interface with Pi/IC: https://gobot.io/
- fm transmitter C/C++ projects such as
- https://github.com/markondej/fm_transmitter
- https://github.com/MundeepL/PiFM
>>>>>>> 7dbdff8 (initial commit)

21
examplerequests.txt Normal file
View File

@ -0,0 +1,21 @@
http://www.subsonic.org/pages/api.jsp
LOGIN
2023/02/03 14:14:30 req /rest/ping.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json GET
2023/02/03 14:14:30 req /rest/ping.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json GET
2023/02/03 14:14:31 req /rest/getAlbumList2.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&type=recent&size=20 GET
2023/02/03 14:14:31 req /rest/getAlbumList2.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&type=frequent&size=20 GET
2023/02/03 14:14:31 req /rest/getAlbumList2.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&type=random&size=20 GET
2023/02/03 14:14:31 req /rest/getRandomSongs.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&size=50 GET
playing music:
2023/02/03 14:17:16 req /rest/stream.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&id=59d5e314f94f72d30df1a20c537e158c&maxBitRate=320&format=mp3&estimateContentLength=false GET
2023/02/03 14:18:07 req /rest/stream.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&id=1bc38cc2c0cfaa302aecdd379abfe938&maxBitRate=320&format=mp3&estimateContentLength=false GET
doorspoelen naar volgende:
2023/02/03 14:17:47 req /rest/scrobble.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&id=97394aea4b552463b3c3519777e5d8ca&submission=false GET

1
go.mod Normal file
View File

@ -0,0 +1 @@
module subfmproxy

72
main.go Normal file
View File

@ -0,0 +1,72 @@
package main
import (
"bytes"
"io"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
)
type Proxy struct {
proxyTarget *url.URL
}
func NewProxy(target string) *Proxy {
proxy := &Proxy{}
urlTarget, err := url.Parse(target)
if err != nil {
log.Fatal("Target not a valid URL!", target)
}
proxy.proxyTarget = urlTarget
return proxy
}
// serves as a reverse proxy to http://www.subsonic.org/pages/api.jsp
func (pr Proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
log.Println("req ", req.RequestURI, req.Method)
proxy := httputil.NewSingleHostReverseProxy(pr.proxyTarget)
// format: 2023/02/03 14:17:16 req /rest/stream.view?u=jefklak&t=8c90da505334799b3184e9fb0539814d&s=LEcB8n9&v=1.13.0&c=substreamer&f=json&id=59d5e314f94f72d30df1a20c537e158c&maxBitRate=320&format=mp3&estimateContentLength=false GET
// returns a binary ID3 file ready to be streamed to the FM receiver system.
// Warning, this does NOT work with Navidrome's native system that also has a /rest/stream endpoint (without the .view)
// TODO wat met "pauzeren"?
// zie https://blog.yossarian.net/2022/11/07/Modernizing-my-1980s-sound-system#fnref:model
if strings.Contains(req.RequestURI, "/rest/stream.view") {
proxy.ModifyResponse = func(resp *http.Response) error {
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
err = resp.Body.Close()
if err != nil {
return err
}
os.WriteFile(strings.ReplaceAll(req.RequestURI, "/", "_")+".txt", body, 0666)
// pass on the original body into a new body 'cause the original one has been read out already.
resp.Body = io.NopCloser(bytes.NewReader(body))
return nil
}
}
// allow for SSL redirection if needed
req.URL.Host = pr.proxyTarget.Host
req.URL.Scheme = pr.proxyTarget.Scheme
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
req.Host = pr.proxyTarget.Host
proxy.ServeHTTP(w, req)
}
func main() {
proxy := NewProxy("http://cd.xavier/")
http.ListenAndServe(":8080", proxy)
}