From 66d3e6402fc2cc27ca3b548aa097f938a758d57a Mon Sep 17 00:00:00 2001 From: nikk gitanes Date: Mon, 6 Sep 2021 03:36:08 +0300 Subject: [PATCH] update dlna --- server/dlna/dlna.go | 3 +++ server/dlna/list.go | 41 ++++++++++++++++++++++++++++++++++++++--- server/dlna/mimetype.go | 35 ++++++++++++++++++++++++----------- server/go.mod | 2 +- 4 files changed, 66 insertions(+), 15 deletions(-) diff --git a/server/dlna/dlna.go b/server/dlna/dlna.go index 6916dfd..b4bd600 100644 --- a/server/dlna/dlna.go +++ b/server/dlna/dlna.go @@ -90,6 +90,9 @@ func Stop() { func onBrowse(path, rootObjectPath, host, userAgent string) (ret []interface{}, err error) { if path == "/" { + ret = getRoot() + return + } else if path == "/Torrents" { ret = getTorrents() return } else if isHashPath(path) { diff --git a/server/dlna/list.go b/server/dlna/list.go index aff56a0..7942183 100644 --- a/server/dlna/list.go +++ b/server/dlna/list.go @@ -4,6 +4,7 @@ import ( "fmt" "net/url" "path/filepath" + "sort" "strconv" "strings" "time" @@ -17,14 +18,41 @@ import ( "server/torr/state" ) +func getRoot() (ret []interface{}) { + + // Root Object + rootObj := upnpav.Object{ + ID: "%2FTorrents", + ParentID: "0", + Title: "Torrents", + Class: "object.container.storageFolder", + Restricted: 1, + Date: upnpav.Timestamp{Time: time.Now()}, + } + + // add Root Object + len := len(torr.ListTorrent()) + cnt := upnpav.Container{Object: rootObj, ChildCount: len} + ret = append(ret, cnt) + + return + +} + func getTorrents() (ret []interface{}) { + torrs := torr.ListTorrent() + // sort by title as in cds SortCaps + sort.Slice(torrs, func(i, j int) bool { + return torrs[i].Title < torrs[j].Title + }) + var vol = 0 for _, t := range torrs { vol++ obj := upnpav.Object{ ID: "%2F" + t.TorrentSpec.InfoHash.HexString(), - ParentID: "0", + ParentID: "%2FTorrents", Title: t.Title, Class: "object.container.storageFolder", Restricted: 1, @@ -38,7 +66,7 @@ func getTorrents() (ret []interface{}) { if vol == 0 { obj := upnpav.Object{ ID: "%2FNo Torrents", - ParentID: "0", + ParentID: "%2FTorrents", Title: "No Torrents", Class: "object.container.storageFolder", Restricted: 1, @@ -46,6 +74,7 @@ func getTorrents() (ret []interface{}) { } cnt := upnpav.Container{Object: obj, ChildCount: 1} ret = append(ret, cnt) + vol = 1 } return } @@ -139,12 +168,17 @@ func getObjFromTorrent(path, parent, host string, torr *torr.Torrent, file *stat mime, err := MimeTypeByPath(file.Path) if err != nil { - log.TLogln("Can't detect mime type", err) + if settings.BTsets.EnableDebug { + log.TLogln("Can't detect mime type", err) + } return } if !mime.IsMedia() { return } + if settings.BTsets.EnableDebug { + log.TLogln("mime type", mime.String(), file.Path) + } obj := upnpav.Object{ ID: parent + "%2F" + file.Path, @@ -163,6 +197,7 @@ func getObjFromTorrent(path, parent, host string, torr *torr.Torrent, file *stat item.Res = append(item.Res, upnpav.Resource{ URL: getLink(host, pathPlay), ProtocolInfo: fmt.Sprintf("http-get:*:%s:%s", mime, dlna.ContentFeatures{ + SupportTimeSeek: true, SupportRange: true, }.String()), Size: uint64(file.Length), diff --git a/server/dlna/mimetype.go b/server/dlna/mimetype.go index 4f5a8f3..b60fb72 100644 --- a/server/dlna/mimetype.go +++ b/server/dlna/mimetype.go @@ -19,29 +19,31 @@ func init() { mimeType string extensions string }{ - {"audio/aac", ".aac"}, + {"image/bmp", ".bmp"}, + {"image/gif", ".gif"}, + {"image/jpeg", ".jpg,.jpeg"}, + {"image/png", ".png"}, + {"image/tiff", ".tiff,.tif"}, + {"audio/x-aac", ".aac"}, {"audio/flac", ".flac"}, {"audio/mpeg", ".mpga,.mpega,.mp2,.mp3,.m4a"}, {"audio/ogg", ".oga,.ogg,.opus,.spx"}, {"audio/opus", ".opus"}, {"audio/weba", ".weba"}, {"audio/x-wav", ".wav"}, - {"image/bmp", ".bmp"}, - {"image/gif", ".gif"}, - {"image/jpeg", ".jpg,.jpeg"}, - {"image/png", ".png"}, - {"image/tiff", ".tiff,.tif"}, {"video/dv", ".dif,.dv"}, {"video/fli", ".fli"}, - {"video/mpeg", ".mpeg,.mpg,.mpe"}, - {"video/mp2t", ".ts,.m2ts,.mts"}, {"video/mp4", ".mp4"}, - {"video/quicktime", ".qt,.mov"}, + {"video/mpeg", ".mpeg,.mpg,.mpe"}, + {"video/x-matroska", ".mpv,.mkv"}, + {"video/mp2t", ".ts,.m2ts,.mts"}, {"video/ogg", ".ogv"}, {"video/webm", ".webm"}, {"video/x-msvideo", ".avi"}, - {"video/x-matroska", ".mpv,.mkv"}, + {"video/x-quicktime", ".qt,.mov"}, {"text/srt", ".srt"}, + {"text/smi", ".smi"}, + {"text/ssa", ".ssa"}, } { for _, ext := range strings.Split(t.extensions, ",") { err := mime.AddExtensionType(ext, t.mimeType) @@ -78,6 +80,11 @@ func (mt mimeType) IsImage() bool { return strings.HasPrefix(string(mt), "image/") } +// IsSub returns true for subtitles MIME-types +func (mt mimeType) IsSub() bool { + return strings.HasPrefix(string(mt), "text/srt") || strings.HasPrefix(string(mt), "text/smi") || strings.HasPrefix(string(mt), "text/ssa") +} + // Returns the group "type", the part before the '/'. func (mt mimeType) Type() string { return strings.SplitN(string(mt), "/", 2)[0] @@ -94,7 +101,13 @@ func MimeTypeByPath(filePath string) (ret mimeType, err error) { if ret == "" { ret, err = mimeTypeByContent(filePath) } - if ret == "video/x-msvideo" { +// Custom DLNA-compat mime mappings +// TODO: make this client headers / profile map + if ret == "video/mp2t" { + ret = "video/mpeg" + else if ret == "video/x-matroska" { + ret = "video/mpeg" + else if ret == "video/x-msvideo" { ret = "video/avi" } else if ret == "" { ret = "application/octet-stream" diff --git a/server/go.mod b/server/go.mod index 48faac2..fb2500e 100644 --- a/server/go.mod +++ b/server/go.mod @@ -3,7 +3,7 @@ module server go 1.17 replace ( - github.com/anacrolix/dms v1.2.2 => github.com/tsynik/dms v0.0.0-20210902055723-0fcf49216c68 + github.com/anacrolix/dms v1.2.2 => github.com/tsynik/dms v0.0.0-20210906003125-e00296ccb6ef github.com/anacrolix/torrent v1.30.3 => github.com/tsynik/torrent v1.2.7-0.20210903201852-d16ba45e0bbd )