This commit is contained in:
YouROK
2021-08-25 22:18:14 +03:00
parent c219e52429
commit 3420fa44ba
11 changed files with 341 additions and 17 deletions

133
server/dlna/dlna.go Normal file
View File

@@ -0,0 +1,133 @@
package dlna
import (
"bytes"
"fmt"
"net"
"os"
"os/user"
"path/filepath"
"time"
"github.com/anacrolix/dms/dlna/dms"
"server/log"
"server/web/pages/template"
)
var dmsServer *dms.Server
func Start() {
dmsServer = &dms.Server{
Interfaces: func() (ifs []net.Interface) {
var err error
ifs, err = net.Interfaces()
if err != nil {
log.TLogln(err)
os.Exit(1)
}
return
}(),
HTTPConn: func() net.Listener {
conn, err := net.Listen("tcp", ":9080")
if err != nil {
log.TLogln(err)
os.Exit(1)
}
return conn
}(),
FriendlyName: getDefaultFriendlyName(),
NoTranscode: true,
NoProbe: true,
Icons: []dms.Icon{
dms.Icon{
Width: 192,
Height: 192,
Depth: 32,
Mimetype: "image/png",
ReadSeeker: bytes.NewReader(template.Androidchrome192x192png),
},
dms.Icon{
Width: 32,
Height: 32,
Depth: 32,
Mimetype: "image/png",
ReadSeeker: bytes.NewReader(template.Favicon32x32png),
},
},
NotifyInterval: 30 * time.Second,
AllowedIpNets: func() []*net.IPNet {
var nets []*net.IPNet
_, ipnet, _ := net.ParseCIDR("0.0.0.0/0")
nets = append(nets, ipnet)
_, ipnet, _ = net.ParseCIDR("::/0")
nets = append(nets, ipnet)
return nets
}(),
OnBrowseDirectChildren: onBrowse,
OnBrowseMetadata: onBrowseMeta,
}
if err := dmsServer.Init(); err != nil {
log.TLogln("error initing dms server: %v", err)
os.Exit(1)
}
go func() {
if err := dmsServer.Run(); err != nil {
log.TLogln(err)
os.Exit(1)
}
}()
}
func Stop() {
if dmsServer != nil {
dmsServer.Close()
dmsServer = nil
}
}
func onBrowse(path, rootObjectPath, host, userAgent string) (ret []interface{}, err error) {
if path == "/" {
ret = getTorrents()
return
} else if isHashPath(path) {
ret = getTorrent(path, host)
return
} else if filepath.Base(path) == "Load Torrent" {
ret = loadTorrent(path, host)
}
return
}
func onBrowseMeta(path string, rootObjectPath string, host, userAgent string) (ret interface{}, err error) {
err = fmt.Errorf("not implemented")
return
}
func getDefaultFriendlyName() string {
ret := "TorrServer"
userName := ""
user, err := user.Current()
if err != nil {
log.TLogln("getDefaultFriendlyName could not get username: %s", err)
} else {
userName = user.Name
}
host, err := os.Hostname()
if err != nil {
log.TLogln("getDefaultFriendlyName could not get hostname: %s", err)
}
if userName == "" && host == "" {
return ret
}
if userName != "" && host != "" {
if userName == host {
return ret + ": " + userName
}
return ret + ": " + userName + " on " + host
}
return ret + ": " + userName + host
}

150
server/dlna/list.go Normal file
View File

@@ -0,0 +1,150 @@
package dlna
import (
"fmt"
"net/url"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/anacrolix/dms/dlna"
"github.com/anacrolix/dms/dlna/dms"
"github.com/anacrolix/dms/upnpav"
"server/log"
"server/settings"
"server/torr"
"server/torr/state"
)
func getTorrents() (ret []interface{}) {
torrs := torr.ListTorrent()
for _, t := range torrs {
obj := upnpav.Object{
ID: "%2F" + t.TorrentSpec.InfoHash.HexString(),
Restricted: 1,
ParentID: "0",
Class: "object.container.storageFolder",
Title: t.Title,
Icon: t.Poster,
AlbumArtURI: t.Poster,
}
cnt := upnpav.Container{Object: obj}
ret = append(ret, cnt)
}
return
}
func getTorrent(path, host string) (ret []interface{}) {
// find torrent without load
torrs := torr.ListTorrent()
var torr *torr.Torrent
for _, t := range torrs {
if strings.Contains(path, t.TorrentSpec.InfoHash.HexString()) {
torr = t
break
}
}
if torr == nil {
return nil
}
parent := "%2F" + torr.TorrentSpec.InfoHash.HexString()
// get content from torrent
// if torrent not loaded, get button for load
if torr.Files() == nil {
obj := upnpav.Object{
ID: parent + "%2FLoad Torrent",
Restricted: 1,
ParentID: parent,
Class: "object.container.storageFolder",
Title: "Load Torrent",
}
cnt := upnpav.Container{Object: obj}
ret = append(ret, cnt)
return
}
ret = loadTorrent(path, host)
return
}
func loadTorrent(path, host string) (ret []interface{}) {
hash := filepath.Base(filepath.Dir(path))
if hash == "/" {
hash = filepath.Base(path)
}
if len(hash) != 40 {
return
}
tor := torr.GetTorrent(hash)
if tor == nil {
log.TLogln("Dlna error get info from torrent", hash)
return
}
if len(tor.Files()) == 0 {
time.Sleep(time.Millisecond * 200)
timeout := time.Now().Add(time.Second * 60)
for {
tor = torr.GetTorrent(hash)
if len(tor.Files()) > 0 {
break
}
time.Sleep(time.Millisecond * 200)
if time.Now().After(timeout) {
return
}
}
}
parent := "%2F" + tor.TorrentSpec.InfoHash.HexString()
files := tor.Status().FileStats
for _, f := range files {
obj := getObjFromTorrent(path, parent, host, tor, f)
if obj != nil {
ret = append(ret, obj)
}
}
return
}
func getLink(host, path string) string {
if !strings.HasPrefix(host, "http") {
host = "http://" + host
}
pos := strings.LastIndex(host, ":")
if pos > 7 {
host = host[:pos]
}
return host + ":" + settings.Port + "/" + path
}
func getObjFromTorrent(path, parent, host string, torr *torr.Torrent, file *state.TorrentFileStat) (ret interface{}) {
mime, err := dms.MimeTypeByPath(file.Path)
if err != nil {
return
}
obj := upnpav.Object{
ID: parent + "%2" + file.Path,
Restricted: 1,
ParentID: parent,
Class: "object.item." + mime.Type() + "Item",
Title: file.Path,
}
item := upnpav.Item{
Object: obj,
Res: make([]upnpav.Resource, 0, 1),
}
pathPlay := "stream/" + url.PathEscape(file.Path) + "?link=" + torr.TorrentSpec.InfoHash.HexString() + "&play&index=" + strconv.Itoa(file.Id)
item.Res = append(item.Res, upnpav.Resource{
URL: getLink(host, pathPlay),
ProtocolInfo: fmt.Sprintf("http-get:*:%s:%s", mime, dlna.ContentFeatures{
SupportRange: true,
}.String()),
Size: uint64(file.Length),
})
return item
}

19
server/dlna/utils.go Normal file
View File

@@ -0,0 +1,19 @@
package dlna
import (
"path/filepath"
)
func isHashPath(path string) bool {
base := filepath.Base(path)
if len(base) == 40 {
data := []byte(base)
for _, v := range data {
if !(v >= 48 && v <= 57 || v >= 65 && v <= 70 || v >= 97 && v <= 102) {
return false
}
}
return true
}
return false
}