Merge branch 'master' into new-torrent

This commit is contained in:
nikk gitanes
2021-09-14 01:19:28 +03:00
9 changed files with 50 additions and 242 deletions

View File

@@ -13,7 +13,6 @@ import (
"github.com/anacrolix/dms/dlna/dms"
"server/log"
"server/utils"
"server/web/pages/template"
)
@@ -30,7 +29,7 @@ func Start() {
}
for _, i := range ifaces {
// interface flags seem to always be 0 on Windows
if runtime.GOOS != "windows" && (i.Flags&net.FlagLoopback != 0 || i.Flags&net.FlagUp == 0 || i.Flags&net.FlagMulticast == 0) || !utils.IsPhysicalInterface(i.HardwareAddr.String()) {
if runtime.GOOS != "windows" && (i.Flags&net.FlagLoopback != 0 || i.Flags&net.FlagUp == 0 || i.Flags&net.FlagMulticast == 0) {
continue
}
ifs = append(ifs, i)
@@ -168,7 +167,7 @@ func getDefaultFriendlyName() string {
var list []string
for _, i := range ifaces {
// interface flags seem to always be 0 on Windows
if runtime.GOOS != "windows" && (i.Flags&net.FlagLoopback != 0 || i.Flags&net.FlagUp == 0 || i.Flags&net.FlagMulticast == 0) || !utils.IsPhysicalInterface(i.HardwareAddr.String()) {
if runtime.GOOS != "windows" && (i.Flags&net.FlagLoopback != 0 || i.Flags&net.FlagUp == 0 || i.Flags&net.FlagMulticast == 0) {
continue
}
addrs, _ := i.Addrs()

View File

@@ -13,6 +13,7 @@ import (
"github.com/anacrolix/dms/upnpav"
"server/log"
mt "server/mimetype"
"server/settings"
"server/torr"
"server/torr/state"
@@ -72,7 +73,7 @@ func getTorrents() (ret []interface{}) {
Class: "object.container.storageFolder",
Date: upnpav.Timestamp{Time: time.Now()},
}
cnt := upnpav.Container{Object: obj, ChildCount: 1}
cnt := upnpav.Container{Object: obj, ChildCount: 0}
ret = append(ret, cnt)
}
return
@@ -114,50 +115,6 @@ func getTorrent(path, host string) (ret []interface{}) {
}
func getTorrentMeta(path, host string) (ret interface{}) {
// https://github.com/1100101/minidlna/blob/ca6dbba18390ad6f8b8d7b7dbcf797dbfd95e2db/upnpsoap.c#L1237-L1243
if path == "/" {
rootObj := upnpav.Object{
ID: "0",
ParentID: "-1",
Restricted: 1,
Searchable: 1,
Title: "TorrServer",
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container",
SearchXML: ` <upnp:searchClass includeDerived="0">object.container.album.musicAlbum</upnp:searchClass>
<upnp:searchClass includeDerived="0">object.container.genre.musicGenre</upnp:searchClass>
<upnp:searchClass includeDerived="0">object.container.person.musicArtist</upnp:searchClass>
<upnp:searchClass includeDerived="0">object.container.playlistContainer</upnp:searchClass>
<upnp:searchClass includeDerived="0">object.container.storageFolder</upnp:searchClass>
<upnp:searchClass includeDerived="0">object.item.audioItem.musicTrack</upnp:searchClass>
<upnp:searchClass includeDerived="0">object.item.imageItem.photo</upnp:searchClass>
<upnp:searchClass includeDerived="1">object.container.album</upnp:searchClass>
<upnp:searchClass includeDerived="1">object.container.genre</upnp:searchClass>
<upnp:searchClass includeDerived="1">object.container</upnp:searchClass>
<upnp:searchClass includeDerived="1">object.item.audioItem</upnp:searchClass>
<upnp:searchClass includeDerived="1">object.item.imageItem</upnp:searchClass>
<upnp:searchClass includeDerived="1">object.item.videoItem</upnp:searchClass>
`,
}
// add Root Object
meta := upnpav.Container{Object: rootObj}
return meta
} else if path == "/TR" {
// TR Object Meta
trObj := upnpav.Object{
ID: "%2FTR",
ParentID: "0",
Restricted: 1,
Searchable: 1,
Title: "Torrents",
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container",
}
//vol := len(torr.ListTorrent())
meta := upnpav.Container{Object: trObj}
return meta
}
// find torrent without load
torrs := torr.ListTorrent()
var torr *torr.Torrent
@@ -172,7 +129,34 @@ func getTorrentMeta(path, host string) (ret interface{}) {
}
// Meta object
if isHashPath(path) {
if path == "/" {
// root object meta
rootObj := upnpav.Object{
ID: "0",
ParentID: "-1",
Restricted: 1,
Searchable: 1,
Title: "TorrServer",
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container.storageFolder",
}
meta := upnpav.Container{Object: rootObj, ChildCount: 1}
return meta
} else if path == "/TR" {
// TR Object Meta
trObj := upnpav.Object{
ID: "%2FTR",
ParentID: "0",
Restricted: 1,
Searchable: 1,
Title: "Torrents",
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container.storageFolder",
}
vol := len(torrs)
meta := upnpav.Container{Object: trObj, ChildCount: vol}
return meta
} else if isHashPath(path) {
// hash object meta
obj := upnpav.Object{
ID: "%2F" + torr.TorrentSpec.InfoHash.HexString(),
@@ -180,15 +164,11 @@ func getTorrentMeta(path, host string) (ret interface{}) {
Restricted: 1,
Title: torr.Title,
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container",
}
meta := upnpav.Container{Object: obj}
meta := upnpav.Container{Object: obj, ChildCount: 1}
return meta
} else if filepath.Base(path) == "LD" {
parent := url.PathEscape(filepath.Dir(path))
if settings.BTsets.EnableDebug {
log.TLogln("getTorrentMeta parent for LD", parent)
}
// LD object meta
obj := upnpav.Object{
ID: parent + "%2FLD",
@@ -197,17 +177,13 @@ func getTorrentMeta(path, host string) (ret interface{}) {
Searchable: 1,
Title: "Load Torrents",
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container",
}
meta := upnpav.Container{Object: obj}
meta := upnpav.Container{Object: obj, ChildCount: 1}
return meta
} else {
file := filepath.Base(path)
id := url.PathEscape(path)
parent := url.PathEscape(filepath.Dir(path))
if settings.BTsets.EnableDebug {
log.TLogln("getTorrentMeta id:", id, "parent:", parent)
}
// file object meta
obj := upnpav.Object{
ID: id,
@@ -216,12 +192,11 @@ func getTorrentMeta(path, host string) (ret interface{}) {
Searchable: 1,
Title: file,
Date: upnpav.Timestamp{Time: time.Now()},
Class: "object.container",
}
meta := upnpav.Container{Object: obj}
meta := upnpav.Container{Object: obj, ChildCount: 1}
return meta
}
// for error response
return nil
}
@@ -277,7 +252,7 @@ func getLink(host, path string) string {
func getObjFromTorrent(path, parent, host string, torr *torr.Torrent, file *state.TorrentFileStat) (ret interface{}) {
mime, err := MimeTypeByPath(file.Path)
mime, err := mt.MimeTypeByPath(file.Path)
if err != nil {
if settings.BTsets.EnableDebug {
log.TLogln("Can't detect mime type", err)

View File

@@ -2,8 +2,7 @@ module server
go 1.17
replace github.com/anacrolix/dms v1.2.2 => github.com/tsynik/dms v0.0.0-20210913075730-e41ecd88369c
replace github.com/anacrolix/dms v1.2.2 => github.com/tsynik/dms v0.0.0-20210911171915-d3d89ee99163
exclude (
github.com/willf/bitset v1.2.0
@@ -21,7 +20,6 @@ require (
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
github.com/pkg/errors v0.9.1
go.etcd.io/bbolt v1.3.6
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
)
@@ -92,6 +90,7 @@ require (
golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e // indirect
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.27.1 // indirect

View File

@@ -156,6 +156,8 @@ github.com/anacrolix/torrent v1.25.1-0.20210224024805-693c30dd889e/go.mod h1:d4V
github.com/anacrolix/torrent v1.28.1-0.20210622065255-582f0ccd48a0/go.mod h1:15VRIA5/DwqbqETbKo3fzlC4aSbB0iMoo10ng3mzAbE=
github.com/anacrolix/torrent v1.29.0/go.mod h1:40Hf2bWxFqTbTWbrdig57JnmYLCjShbWWjdbB3VN5n4=
github.com/anacrolix/torrent v1.30.2/go.mod h1:vbNxKfaGiNq8edcCaQI1oSNJwh4GMqtMUMF9qOdZ6C0=
github.com/anacrolix/torrent v1.31.1-0.20210912041407-4691b0b8d194 h1:U1h0guD86azvKs/sepNTrYUacoofSLxRQJwfd54IxgY=
github.com/anacrolix/torrent v1.31.1-0.20210912041407-4691b0b8d194/go.mod h1:akZJHHFN8aWH2lcPZQ0I3etujnenwYpUvj36HV9uvAI=
github.com/anacrolix/upnp v0.1.1/go.mod h1:LXsbsp5h+WGN7YR+0A7iVXm5BL1LYryDev1zuJMWYQo=
github.com/anacrolix/upnp v0.1.2-0.20200416075019-5e9378ed1425 h1:/Wi6l2ONI1FUFWN4cBwHOO90V4ylp4ud/eov6GUcVFk=
github.com/anacrolix/upnp v0.1.2-0.20200416075019-5e9378ed1425/go.mod h1:Pz94W3kl8rf+wxH3IbCa9Sq+DTJr8OSbV2Q3/y51vYs=
@@ -720,8 +722,8 @@ github.com/tinylib/msgp v1.1.1/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tsynik/dms v0.0.0-20210913075730-e41ecd88369c h1:4yU1p5MmRu+233Hs2OhR8Kx9gOWw20KR2AY1py5pLvA=
github.com/tsynik/dms v0.0.0-20210913075730-e41ecd88369c/go.mod h1:oWW4QbQ9YGl+FJ1X8xcrUYVObfA/KdipoeBuTC4ltG8=
github.com/tsynik/dms v0.0.0-20210911171915-d3d89ee99163 h1:qBZPOad8wOmvFe6rIx1d0U7VpymFalvbM5kjHeEx8Gs=
github.com/tsynik/dms v0.0.0-20210911171915-d3d89ee99163/go.mod h1:oWW4QbQ9YGl+FJ1X8xcrUYVObfA/KdipoeBuTC4ltG8=
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=

View File

@@ -1,4 +1,4 @@
package dlna
package mimetype
import (
"log"

View File

@@ -12,6 +12,7 @@ import (
"github.com/anacrolix/missinggo/httptoo"
"github.com/anacrolix/torrent"
mt "server/mimetype"
sets "server/settings"
"server/torr/state"
)
@@ -61,8 +62,12 @@ func (t *Torrent) Stream(fileID int, req *http.Request, resp http.ResponseWriter
resp.Header().Set("Connection", "close")
resp.Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", t.Hash().HexString(), file.Path())))
// DLNA headers
resp.Header().Set("transferMode.dlna.org", "Streaming")
mime, err := mt.MimeTypeByPath(file.Path())
if err == nil && mime.IsMedia() {
resp.Header().Set("content-type", mime.String())
}
if req.Header.Get("getContentFeatures.dlna.org") != "" {
resp.Header().Set("contentFeatures.dlna.org", dlna.ContentFeatures{
SupportRange: true,

View File

@@ -1,38 +0,0 @@
package utils
import (
"strings"
)
type PhysicalInterface struct {
MACAddress string
Name string
FriendlyName string
}
// Mac Address parts to look for, and identify non physical devices. There may be more, update me!
var macAddrPartsToFilter []string = []string{
"00:03:FF", // Microsoft Hyper-V, Virtual Server, Virtual PC
"0A:00:27", // VirtualBox
"00:00:00:00:00", // Teredo Tunneling Pseudo-Interface
"00:50:56", // VMware ESX 3, Server, Workstation, Player
"00:1C:14", // VMware ESX 3, Server, Workstation, Player
"00:0C:29", // VMware ESX 3, Server, Workstation, Player
"00:05:69", // VMware ESX 3, Server, Workstation, Player
"00:1C:42", // Microsoft Hyper-V, Virtual Server, Virtual PC
"00:0F:4B", // Virtual Iron 4
"00:16:3E", // Red Hat Xen, Oracle VM, XenSource, Novell Xen
"08:00:27", // Sun xVM VirtualBox
"7A:79", // Hamachi
}
// Filters the possible physical interface address by comparing it to known popular VM Software adresses
// and Teredo Tunneling Pseudo-Interface.
func IsPhysicalInterface(addr string) bool {
for _, macPart := range macAddrPartsToFilter {
if strings.HasPrefix(strings.ToLower(addr), strings.ToLower(macPart)) {
return false
}
}
return true
}

View File

@@ -1,29 +0,0 @@
//go:build linux || darwin
// +build linux darwin
package utils
import (
"fmt"
"net"
)
// Gets all physical interfaces based on filter results, ignoring all VM, Loopback and Tunnel interfaces.
func GetAllPhysicalInterfaces() []PhysicalInterface {
ifaces, err := net.Interfaces()
if err != nil {
fmt.Println(err)
return nil
}
var outInterfaces []PhysicalInterface
for _, element := range ifaces {
if element.Flags&net.FlagLoopback == 0 && element.Flags&net.FlagUp == 1 && IsPhysicalInterface(element.HardwareAddr.String()) {
outInterfaces = append(outInterfaces, PhysicalInterface{MACAddress: element.HardwareAddr.String(), Name: element.Name, FriendlyName: element.Name})
}
}
return outInterfaces
}

View File

@@ -1,105 +0,0 @@
//go:build windows
// +build windows
package utils
import (
"os"
"syscall"
"unicode/utf16"
"unsafe"
"golang.org/x/sys/windows"
)
const (
IfOperStatusUp = 1
IF_TYPE_SOFTWARE_LOOPBACK = 24
IF_TYPE_TUNNEL = 131
)
const hexDigit = "0123456789abcdef"
func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
var b []byte
l := uint32(15000) // recommended initial size
for {
b = make([]byte, l)
err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
if err == nil {
if l == 0 {
return nil, nil
}
break
}
if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
if l <= uint32(len(b)) {
return nil, os.NewSyscallError("getadaptersaddresses", err)
}
}
var aas []*windows.IpAdapterAddresses
for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
aas = append(aas, aa)
}
return aas, nil
}
func bytePtrToString(p *uint8) string {
a := (*[10000]uint8)(unsafe.Pointer(p))
i := 0
for a[i] != 0 {
i++
}
return string(a[:i])
}
func physicalAddrToString(physAddr [8]byte) string {
if len(physAddr) == 0 {
return ""
}
buf := make([]byte, 0, len(physAddr)*3-1)
for i, b := range physAddr {
if i > 0 {
buf = append(buf, ':')
}
buf = append(buf, hexDigit[b>>4])
buf = append(buf, hexDigit[b&0xF])
}
return string(buf)
}
func cStringToString(cs *uint16) (s string) {
if cs != nil {
us := make([]uint16, 0, 256)
for p := uintptr(unsafe.Pointer(cs)); ; p += 2 {
u := *(*uint16)(unsafe.Pointer(p))
if u == 0 {
return string(utf16.Decode(us))
}
us = append(us, u)
}
}
return ""
}
// Gets all physical interfaces based on filter results, ignoring all VM, Loopback and Tunnel interfaces.
func GetAllPhysicalInterfaces() []PhysicalInterface {
aa, _ := adapterAddresses()
var outInterfaces []PhysicalInterface
for _, pa := range aa {
mac := physicalAddrToString(pa.PhysicalAddress)
name := "\\Device\\NPF_" + bytePtrToString(pa.AdapterName)
if pa.IfType != uint32(IF_TYPE_SOFTWARE_LOOPBACK) && pa.IfType != uint32(IF_TYPE_TUNNEL) &&
pa.OperStatus == uint32(IfOperStatusUp) && IsPhysicalInterface(mac) {
outInterfaces = append(outInterfaces, PhysicalInterface{MACAddress: mac, Name: name, FriendlyName: cStringToString(pa.FriendlyName)})
}
}
return outInterfaces
}