Skip to content

Commit

Permalink
Initial support for DeoVR remote protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
cld9x committed Dec 3, 2020
1 parent c08fccf commit d863d5e
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 39 deletions.
59 changes: 20 additions & 39 deletions pkg/api/deovr.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package api
import (
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"strconv"
"strings"

Expand All @@ -14,6 +12,7 @@ import (
restfulspec "github.com/emicklei/go-restful-openapi"
"github.com/markphelps/optional"
"github.com/xbapps/xbvr/pkg/common"
"github.com/xbapps/xbvr/pkg/deo_remote"
"github.com/xbapps/xbvr/pkg/models"
)

Expand Down Expand Up @@ -91,6 +90,13 @@ type DeoSceneVideoSource struct {
URL string `json:"url"`
}

func setDeoPlayerHost(req *restful.Request) {
deoIP := strings.Split(req.Request.RemoteAddr, ":")[0]
if deoIP != deo_remote.DeoPlayerHost {
common.Log.Infof("DeoVR Player connecting from %v", deoIP)
deo_remote.DeoPlayerHost = deoIP
}
}

func restfulAuthFilter(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
if common.IsDeoAuthEnabled() {
Expand Down Expand Up @@ -138,6 +144,8 @@ func (i DeoVRResource) WebService() *restful.WebService {
Consumes(restful.MIME_JSON, "application/x-www-form-urlencoded").
Produces(restful.MIME_JSON)

ws.Route(ws.HEAD("").To(i.getDeoLibrary))

ws.Route(ws.GET("").Filter(restfulAuthFilter).To(i.getDeoLibrary).
Metadata(restfulspec.KeyOpenAPITags, tags).
Writes(DeoLibrary{}))
Expand All @@ -163,6 +171,8 @@ func (i DeoVRResource) WebService() *restful.WebService {
}

func (i DeoVRResource) getDeoFile(req *restful.Request, resp *restful.Response) {
setDeoPlayerHost(req)

db, _ := models.GetDB()
defer db.Close()

Expand All @@ -176,14 +186,8 @@ func (i DeoVRResource) getDeoFile(req *restful.Request, resp *restful.Response)
var file models.File
db.Where(&models.File{ID: uint(fileId)}).First(&file)

//TODO: remove temporary workaround, once DeoVR doesn't block hi-res videos anymore
var height = file.VideoHeight
var width = file.VideoWidth
if height > 2160 {
height = height / 10
width = width / 10
}

var sources []DeoSceneEncoding
sources = append(sources, DeoSceneEncoding{
Name: fmt.Sprintf("File 1/1 - %v", humanize.Bytes(uint64(file.Size))),
Expand All @@ -193,7 +197,7 @@ func (i DeoVRResource) getDeoFile(req *restful.Request, resp *restful.Response)
Height: height,
Width: width,
Size: file.Size,
URL: fmt.Sprintf("%v/api/dms/file/%v", baseURL, file.ID),
URL: fmt.Sprintf("%v/api/dms/file/%v?dnt=1", baseURL, file.ID),
},
},
})
Expand All @@ -214,6 +218,8 @@ func (i DeoVRResource) getDeoFile(req *restful.Request, resp *restful.Response)
}

func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response) {
setDeoPlayerHost(req)

db, _ := models.GetDB()
defer db.Close()

Expand Down Expand Up @@ -249,13 +255,9 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response)

var sources []DeoSceneEncoding
for i := range scene.Files {
//TODO: remove temporary workaround, once DeoVR doesn't block hi-res videos anymore
var height = scene.Files[i].VideoHeight
var width = scene.Files[i].VideoWidth
if height > 2160 {
height = height / 10
width = width / 10
}

sources = append(sources, DeoSceneEncoding{
Name: fmt.Sprintf("File %v/%v %vp - %v", i+1, len(scene.Files), scene.Files[i].VideoHeight, humanize.Bytes(uint64(scene.Files[i].Size))),
VideoSources: []DeoSceneVideoSource{
Expand All @@ -264,7 +266,7 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response)
Height: height,
Width: width,
Size: scene.Files[i].Size,
URL: fmt.Sprintf("%v/api/dms/file/%v", baseURL, scene.Files[i].ID),
URL: fmt.Sprintf("%v/api/dms/file/%v?dnt=1", baseURL, scene.Files[i].ID),
},
},
})
Expand Down Expand Up @@ -319,6 +321,8 @@ func (i DeoVRResource) getDeoScene(req *restful.Request, resp *restful.Response)
}

func (i DeoVRResource) getDeoLibrary(req *restful.Request, resp *restful.Response) {
setDeoPlayerHost(req)

db, _ := models.GetDB()
defer db.Close()

Expand Down Expand Up @@ -362,29 +366,6 @@ func (i DeoVRResource) getDeoLibrary(req *restful.Request, resp *restful.Respons
})
}

func getBaseURL() string {
hostname, err := os.Hostname()
if err != nil {
return "unknown"
}

addrs, err := net.LookupIP(hostname)
if err != nil {
return hostname
}

for _, addr := range addrs {
if ipv4 := addr.To4(); ipv4 != nil {
ip, err := ipv4.MarshalText()
if err != nil {
return hostname
}
return string(ip)
}
}
return hostname
}

func scenesToDeoList(req *restful.Request, scenes []models.Scene) []DeoListItem {
baseURL := "http://" + req.Request.Host

Expand Down Expand Up @@ -415,7 +396,7 @@ func filesToDeoList(req *restful.Request, files []models.File) []DeoListItem {
Title: files[i].Filename,
VideoLength: int(files[i].VideoDuration),
ThumbnailURL: baseURL + "/ui/images/blank.png",
VideoURL: baseURL + "/deovr/file/" + fmt.Sprint(files[i].ID),
VideoURL: fmt.Sprintf("%v/api/dms/file/%v?dnt=1", baseURL, files[i].ID),
}
list = append(list, item)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/common/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var BinDir string
var CacheDir string
var ImgDir string
var MetricsDir string
var HeatmapDir string
var IndexDirV2 string
var ScrapeCacheDir string
var VideoPreviewDir string
Expand All @@ -39,6 +40,7 @@ func InitPaths() {
BinDir = filepath.Join(AppDir, "bin")
ImgDir = filepath.Join(AppDir, "imageproxy")
MetricsDir = filepath.Join(AppDir, "metrics")
HeatmapDir = filepath.Join(AppDir, "heatmap")
IndexDirV2 = filepath.Join(AppDir, "search-v2")

ScrapeCacheDir = filepath.Join(CacheDir, "scrape_cache")
Expand All @@ -52,6 +54,7 @@ func InitPaths() {
_ = os.MkdirAll(AppDir, os.ModePerm)
_ = os.MkdirAll(ImgDir, os.ModePerm)
_ = os.MkdirAll(MetricsDir, os.ModePerm)
_ = os.MkdirAll(HeatmapDir, os.ModePerm)
_ = os.MkdirAll(CacheDir, os.ModePerm)
_ = os.MkdirAll(BinDir, os.ModePerm)
_ = os.MkdirAll(IndexDirV2, os.ModePerm)
Expand Down
94 changes: 94 additions & 0 deletions pkg/deo_remote/remote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package deo_remote

import (
"encoding/binary"
"encoding/json"
"net"
"time"

"github.com/xbapps/xbvr/pkg/common"
)

type DeoPacket struct {
Path string `json:"path,omitempty"`
Duration float64 `json:"duration,omitempty"`
CurrentTime float64 `json:"currentTime,omitempty"`
PlaybackSpeed float64 `json:"playbackSpeed,omitempty"`
PlayerState int `json:"playerState,omitempty"`
}

const PLAYING = 0
const PAUSED = 1

var DeoPlayerHost = ""

func DeoRemote() {
for {
deoLoop()
time.Sleep(1 * time.Second)
}
}

func deoLoop() error {
if DeoPlayerHost == "" {
return nil
}
conn, err := net.Dial("tcp", DeoPlayerHost+":23554")
if err != nil {
return err
}

common.Log.Info("Connected to DeoVR")

for {
// Read
err := conn.SetReadDeadline(time.Now().Add(2 * time.Second))
if err != nil {
return err
}

// Check incoming packet length
lenBuf := make([]byte, 4)
_, err = conn.Read(lenBuf[:]) // recv data
bodyLength := binary.LittleEndian.Uint32(lenBuf)

// Read packet
if bodyLength > 0 {
recvBuf := make([]byte, bodyLength)
_, err = conn.Read(recvBuf[:]) // recv data
if err != nil {
return err
}

packet := decodePacket(recvBuf)
go TrackSession(packet)
}

// Write
err = conn.SetWriteDeadline(time.Now().Add(1 * time.Second))
if err != nil {
return err
}

// Check if there's command queued, otherwise send ping packet
packet := encodePacket(DeoPacket{})
_, err = conn.Write(packet)
if err != nil {
return err
}
}
}

func encodePacket(packet DeoPacket) []byte {
data, _ := json.Marshal(packet)
header := make([]byte, 4)
binary.LittleEndian.PutUint32(header, uint32(len(data)))

return append(header, data...)
}

func decodePacket(data []byte) DeoPacket {
var packet DeoPacket
json.Unmarshal(data, &packet)
return packet
}
Loading

0 comments on commit d863d5e

Please sign in to comment.