Skip to content

Commit

Permalink
Merge pull request #5 from alexballas/feature/interactive_terminal
Browse files Browse the repository at this point in the history
Feature/interactive terminal
  • Loading branch information
alexballas authored Feb 21, 2021
2 parents d72510c + 6bf9920 commit 284ce33
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 49 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

Go2TV lets you cast your videos to any UPnP/DLNA MediaRenderer like Samsumg TVs.

![](https://i.imgur.com/fnYkkp7.gif)
![](https://i.imgur.com/BsMevHi.gif)

Usage
-----
Expand All @@ -19,6 +19,8 @@ Usage of go2tv:
Cast to a specific UPnP/DLNA MediaRenderer URL.
-v string
Path to the video file.
-version
Print version.
```

Build requirements
Expand Down
15 changes: 12 additions & 3 deletions flagfuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ func listFlagFunction() error {
}

func checkflags() (bool, error) {
checkVerflag()

if err := checkVflag(); err != nil {
return false, err
}
Expand All @@ -57,7 +59,7 @@ func checkflags() (bool, error) {
return false, err
}

if list == true {
if list {
return true, nil
}

Expand All @@ -69,7 +71,7 @@ func checkflags() (bool, error) {
}

func checkVflag() error {
if *listPtr == false {
if !*listPtr {
if *videoArg == "" {
err := errors.New("No video file defined")
return err
Expand Down Expand Up @@ -121,11 +123,18 @@ func checkTflag() error {
}

func checkLflag() (bool, error) {
if *listPtr == true {
if *listPtr {
if err := listFlagFunction(); err != nil {
return false, err
}
return true, nil
}
return false, nil
}

func checkVerflag() {
if *versionPtr {
fmt.Println("1.2")
os.Exit(0)
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module github.com/alexballas/go2tv
go 1.15

require (
github.com/gdamore/tcell/v2 v2.1.0
github.com/koron/go-ssdp v0.0.2
github.com/mattn/go-runewidth v0.0.10
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
)
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.1.0 h1:UnSmozHgBkQi2PGsFr+rpdXuAPRRucMegpQp3Z3kDro=
github.com/gdamore/tcell/v2 v2.1.0/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o=
github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
39 changes: 16 additions & 23 deletions go2tv.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"errors"
"flag"
"fmt"
"net/url"
"os"
"os/signal"
"path/filepath"
"sort"
"syscall"

"github.com/alexballas/go2tv/httphandlers"
"github.com/alexballas/go2tv/interactive"
"github.com/alexballas/go2tv/iptools"
"github.com/alexballas/go2tv/soapcalls"
"github.com/koron/go-ssdp"
Expand All @@ -24,6 +24,7 @@ var (
subsArg = flag.String("s", "", "Path to the subtitles file.")
listPtr = flag.Bool("l", false, "List all available UPnP/DLNA MediaRenderer models and URLs.")
targetPtr = flag.String("t", "", "Cast to a specific UPnP/DLNA MediaRenderer URL.")
versionPtr = flag.Bool("version", false, "Print version.")
)

func main() {
Expand All @@ -48,31 +49,36 @@ func main() {
whereToListen, err := iptools.URLtoListenIPandPort(dmrURL)
check(err)

newsc, err := interactive.InitNewScreen()
check(err)

// The String() method of the net/url package will properly escape
// the URL compared to the url.QueryEscape() method.
videoFileURLencoded := &url.URL{Path: filepath.Base(absVideoFile)}
subsFileURLencoded := &url.URL{Path: filepath.Base(absSubtitlesFile)}

tvdata := &soapcalls.TVPayload{
TransportURL: transportURL,
ControlURL: controlURL,
CallbackURL: "http://" + whereToListen + "/callback",
VideoURL: "http://" + whereToListen + "/" + filepath.Base(absVideoFile),
SubtitlesURL: "http://" + whereToListen + "/" + filepath.Base(absSubtitlesFile),
VideoURL: "http://" + whereToListen + "/" + videoFileURLencoded.String(),
SubtitlesURL: "http://" + whereToListen + "/" + subsFileURLencoded.String(),
}

s := httphandlers.NewServer(whereToListen)

// We pass the tvdata here as we need the callback handlers to be able to
// react to the different media renderer states.
go func() {
s.ServeFiles(serverStarted, absVideoFile, absSubtitlesFile, &httphandlers.TVPayload{Soapcalls: *tvdata})
s.ServeFiles(serverStarted, absVideoFile, absSubtitlesFile, &httphandlers.HTTPPayload{Soapcalls: tvdata, Screen: newsc})
}()
// Wait for HTTP server to properly initialize
<-serverStarted

err = tvdata.SendtoTV("Play")
err = tvdata.SendtoTV("Play1")
check(err)

initializeCloseHandler(*tvdata)

// Sleep forever.
select {}
newsc.InterInit(*tvdata)
}

func loadSSDPservices() error {
Expand Down Expand Up @@ -114,19 +120,6 @@ func devicePicker(i int) (string, error) {
return "", errors.New("devicePicker: Something went terribly wrong")
}

func initializeCloseHandler(tvdata soapcalls.TVPayload) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
fmt.Println(" Shutting down...")
err := tvdata.SendtoTV("Stop")
check(err)

os.Exit(0)
}()
}

func check(err error) {
if err != nil {
fmt.Fprintf(os.Stderr, "Encountered error(s): %s\n", err)
Expand Down
26 changes: 14 additions & 12 deletions httphandlers/httphandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"

"github.com/alexballas/go2tv/interactive"
"github.com/alexballas/go2tv/soapcalls"
)

Expand All @@ -25,15 +26,16 @@ type HTTPserver struct {
mux *http.ServeMux
}

// TVPayload - We need some of the soapcalls magic in
// HTTPPayload - We need some of the soapcalls magic in
// this package too. We need to expose the ControlURL
// to the callback handler.
type TVPayload struct {
Soapcalls soapcalls.TVPayload
type HTTPPayload struct {
Soapcalls *soapcalls.TVPayload
Screen *interactive.NewScreen
}

// ServeFiles - Start HTTP server and serve the files.
func (s *HTTPserver) ServeFiles(serverStarted chan<- struct{}, videoPath, subtitlesPath string, tvpayload *TVPayload) {
func (s *HTTPserver) ServeFiles(serverStarted chan<- struct{}, videoPath, subtitlesPath string, tvpayload *HTTPPayload) {

files := &filesToServe{
Video: videoPath,
Expand All @@ -48,7 +50,6 @@ func (s *HTTPserver) ServeFiles(serverStarted chan<- struct{}, videoPath, subtit
check(err)

serverStarted <- struct{}{}
fmt.Println("Listening on:", s.http.Addr)
s.http.Serve(ln)

}
Expand All @@ -63,8 +64,8 @@ func (f *filesToServe) serveVideoHandler(w http.ResponseWriter, req *http.Reques
w.Header().Set("contentFeatures.dlna.org", "DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=017000 00000000000000000000000000")

filePath, err := os.Open(f.Video)
defer filePath.Close()
check(err)
defer filePath.Close()

fileStat, err := filePath.Stat()
check(err)
Expand All @@ -77,11 +78,11 @@ func (f *filesToServe) serveSubtitlesHandler(w http.ResponseWriter, req *http.Re
w.Header().Set("contentFeatures.dlna.org", "DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=017000 00000000000000000000000000")

filePath, err := os.Open(f.Subtitles)
defer filePath.Close()
if err != nil {
http.Error(w, "", 404)
return
}
defer filePath.Close()

fileStat, err := filePath.Stat()
if err != nil {
Expand All @@ -91,7 +92,7 @@ func (f *filesToServe) serveSubtitlesHandler(w http.ResponseWriter, req *http.Re
http.ServeContent(w, req, filepath.Base(f.Subtitles), fileStat.ModTime(), filePath)
}

func (p *TVPayload) callbackHandler(w http.ResponseWriter, req *http.Request) {
func (p *HTTPPayload) callbackHandler(w http.ResponseWriter, req *http.Request) {
reqParsed, _ := io.ReadAll(req.Body)
sidVal, sidExists := req.Header["Sid"]

Expand All @@ -109,7 +110,6 @@ func (p *TVPayload) callbackHandler(w http.ResponseWriter, req *http.Request) {
uuid = strings.TrimLeft(uuid, "[")
uuid = strings.TrimLeft(uuid, "]")
uuid = strings.TrimLeft(uuid, "uuid:")

// Apparently we should ignore the first message
// On some media renderers we receive a STOPPED message
// even before we start streaming.
Expand All @@ -132,19 +132,21 @@ func (p *TVPayload) callbackHandler(w http.ResponseWriter, req *http.Request) {
http.Error(w, "", 404)
return
}

if !soapcalls.UpdateMRstate(previousstate, newstate, uuid) {
http.Error(w, "", 404)
return
}
if newstate == "PLAYING" {
fmt.Println("Received: Playing")
p.Screen.EmmitMsg("Playing")
}
if newstate == "PAUSED_PLAYBACK" {
fmt.Println("Received: Paused")
p.Screen.EmmitMsg("Paused")
}
if newstate == "STOPPED" {
fmt.Println("Received: Stopped")
p.Screen.EmmitMsg("Stopped")
p.Soapcalls.UnsubscribeSoapCall(uuid)
p.Screen.Current.Fini()
os.Exit(0)
}
// TODO - Properly reply to that.
Expand Down
Loading

0 comments on commit 284ce33

Please sign in to comment.