Merge branch 'master' into new-torrent

This commit is contained in:
nikk gitanes
2021-08-27 18:40:53 +03:00
26 changed files with 3390 additions and 2778 deletions

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

@@ -0,0 +1,161 @@
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: 32,
Height: 32,
Depth: 32,
Mimetype: "image/png",
ReadSeeker: bytes.NewReader(template.Favicon32x32png),
},
dms.Icon{
Width: 192,
Height: 192,
Depth: 32,
Mimetype: "image/png",
ReadSeeker: bytes.NewReader(template.Androidchrome192x192png),
},
},
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
}
if host == "localhost" { // useless host, use 1st IP
ifaces, err := net.Interfaces()
if err != nil {
return ret + ": " + userName + "@" + host
}
var list []string
for _, i := range ifaces {
addrs, _ := i.Addrs()
if i.Flags&net.FlagUp == net.FlagUp {
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if !ip.IsLoopback() {
list = append(list, ip.String())
}
}
}
}
if len(list) > 0 {
return ret + " " + list[0]
}
}
return ret + ": " + userName + "@" + host
}

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

@@ -0,0 +1,160 @@
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"
"server/utils"
)
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
}
// get content from torrent
parent := "%2F" + torr.TorrentSpec.InfoHash.HexString()
// 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{}) {
// only playable files
if utils.GetMimeType(file.Path) == "*/*" {
return
}
mime, err := dms.MimeTypeByPath(file.Path)
if err != nil {
//return // this always err
if utils.GetMimeType(file.Path) == "video/*" {
mime = "video/mpeg"
} else {
mime = "audio/mpeg"
}
}
obj := upnpav.Object{
ID: parent + "%2F" + 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
}

View File

@@ -2,8 +2,15 @@ module server
go 1.17 go 1.17
replace (
github.com/anacrolix/dms v1.2.2 => github.com/yourok/dms v0.0.0-20210826085116-42eca44e0aef
)
exclude github.com/willf/bitset v1.2.0
require ( require (
github.com/alexflint/go-arg v1.3.0 github.com/alexflint/go-arg v1.3.0
github.com/anacrolix/dms v1.2.2
github.com/anacrolix/missinggo v1.3.0 github.com/anacrolix/missinggo v1.3.0
github.com/anacrolix/torrent v1.30.4 github.com/anacrolix/torrent v1.30.4
github.com/gin-contrib/cors v1.3.1 github.com/gin-contrib/cors v1.3.1
@@ -22,8 +29,7 @@ require (
github.com/anacrolix/chansync v0.1.0 // indirect github.com/anacrolix/chansync v0.1.0 // indirect
github.com/anacrolix/confluence v1.8.0 // indirect github.com/anacrolix/confluence v1.8.0 // indirect
github.com/anacrolix/dht/v2 v2.10.3 // indirect github.com/anacrolix/dht/v2 v2.10.3 // indirect
github.com/anacrolix/envpprof v1.1.1 // indirect github.com/anacrolix/ffprobe v1.0.0 // indirect
github.com/anacrolix/go-libutp v1.0.4 // indirect
github.com/anacrolix/log v0.9.0 // indirect github.com/anacrolix/log v0.9.0 // indirect
github.com/anacrolix/missinggo/perf v1.0.0 // indirect github.com/anacrolix/missinggo/perf v1.0.0 // indirect
github.com/anacrolix/missinggo/v2 v2.5.2 // indirect github.com/anacrolix/missinggo/v2 v2.5.2 // indirect

View File

@@ -68,6 +68,8 @@ github.com/anacrolix/envpprof v1.0.1/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAK
github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4= github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
github.com/anacrolix/envpprof v1.1.1 h1:sHQCyj7HtiSfaZAzL2rJrQdyS7odLqlwO6nhk/tG/j8= github.com/anacrolix/envpprof v1.1.1 h1:sHQCyj7HtiSfaZAzL2rJrQdyS7odLqlwO6nhk/tG/j8=
github.com/anacrolix/envpprof v1.1.1/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4= github.com/anacrolix/envpprof v1.1.1/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
github.com/anacrolix/ffprobe v1.0.0 h1:j8fGLBsXejwdXd0pkA9iR3Dt1XwMFv5wjeYWObcue8A=
github.com/anacrolix/ffprobe v1.0.0/go.mod h1:BIw+Bjol6CWjm/CRWrVLk2Vy+UYlkgmBZ05vpSYqZPw=
github.com/anacrolix/go-libutp v0.0.0-20180522111405-6baeb806518d/go.mod h1:beQSaSxwH2d9Eeu5ijrEnHei5Qhk+J6cDm1QkWFru4E= github.com/anacrolix/go-libutp v0.0.0-20180522111405-6baeb806518d/go.mod h1:beQSaSxwH2d9Eeu5ijrEnHei5Qhk+J6cDm1QkWFru4E=
github.com/anacrolix/go-libutp v1.0.2/go.mod h1:uIH0A72V++j0D1nnmTjjZUiH/ujPkFxYWkxQ02+7S0U= github.com/anacrolix/go-libutp v1.0.2/go.mod h1:uIH0A72V++j0D1nnmTjjZUiH/ujPkFxYWkxQ02+7S0U=
github.com/anacrolix/go-libutp v1.0.4 h1:95sv09MoNQbgEJqJLrotglFnVBAiMx1tyl6xMAmnAgg= github.com/anacrolix/go-libutp v1.0.4 h1:95sv09MoNQbgEJqJLrotglFnVBAiMx1tyl6xMAmnAgg=
@@ -467,6 +469,7 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
@@ -712,6 +715,8 @@ github.com/willf/bloom v0.0.0-20170505221640-54e3b963ee16/go.mod h1:MmAltL9pDMNT
github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX8Wdm2/JPA= github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX8Wdm2/JPA=
github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8= github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yourok/dms v0.0.0-20210826085116-42eca44e0aef h1:8W9j6a/BpZjss9p6GkD5xvmLtONhWkkWT3XoRPtje0g=
github.com/yourok/dms v0.0.0-20210826085116-42eca44e0aef/go.mod h1:1GqMUla/yTV3GFjpKMpmdntkTl6aslGK3jfIksEwIdI=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
@@ -802,6 +807,7 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210420210106-798c2154c571/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210420210106-798c2154c571/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210427231257-85d9c07bbe3a/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210427231257-85d9c07bbe3a/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -873,6 +879,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210415045647-66c3f260301c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -26,6 +26,7 @@ func Start(port string, roSets bool) {
os.Exit(1) os.Exit(1)
} else { } else {
go cleanCache() go cleanCache()
settings.Port = port
web.Start(port) web.Start(port)
} }
} }

View File

@@ -27,6 +27,9 @@ type BTSets struct {
TorrentDisconnectTimeout int // in seconds TorrentDisconnectTimeout int // in seconds
EnableDebug bool // print logs EnableDebug bool // print logs
// DLNA
EnableDLNA bool
// BT Config // BT Config
EnableIPv6 bool EnableIPv6 bool
DisableTCP bool DisableTCP bool

View File

@@ -10,6 +10,7 @@ import (
var ( var (
tdb *TDB tdb *TDB
Path string Path string
Port string
ReadOnly bool ReadOnly bool
HttpAuth bool HttpAuth bool
) )

View File

@@ -101,7 +101,7 @@ func GetTorrent(hashHex string) *Torrent {
go func() { go func() {
lockApi.Lock() lockApi.Lock()
defer lockApi.Unlock() defer lockApi.Unlock()
log.TLogln("Add torrent") log.TLogln("New torrent", tor.Hash())
tr, _ := NewTorrent(tor.TorrentSpec, bts) tr, _ := NewTorrent(tor.TorrentSpec, bts)
if tr != nil { if tr != nil {
tr.Title = tor.Title tr.Title = tor.Title

View File

@@ -79,6 +79,7 @@ func (bt *BTServer) configure() {
bt.config.HTTPUserAgent = userAgent bt.config.HTTPUserAgent = userAgent
bt.config.ExtendedHandshakeClientVersion = cliVers bt.config.ExtendedHandshakeClientVersion = cliVers
bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit
bt.config.TotalHalfOpenConns = 500
// Encryption/Obfuscation // Encryption/Obfuscation
bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{ bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{
RequirePreferred: settings.BTsets.ForceEncrypt, RequirePreferred: settings.BTsets.ForceEncrypt,

View File

@@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/pkg/errors" "github.com/pkg/errors"
"server/dlna"
sets "server/settings" sets "server/settings"
"server/torr" "server/torr"
@@ -29,10 +30,15 @@ func settings(c *gin.Context) {
return return
} else if req.Action == "set" { } else if req.Action == "set" {
torr.SetSettings(req.Sets) torr.SetSettings(req.Sets)
dlna.Stop()
if req.Sets.EnableDLNA {
dlna.Start()
}
c.Status(200) c.Status(200)
return return
} else if req.Action == "def" { } else if req.Action == "def" {
torr.SetDefSettings() torr.SetDefSettings()
dlna.Stop()
c.Status(200) c.Status(200)
return return
} }

View File

@@ -6,6 +6,8 @@ import (
"github.com/gin-contrib/cors" "github.com/gin-contrib/cors"
"github.com/gin-contrib/location" "github.com/gin-contrib/location"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"server/dlna"
"server/settings"
"server/log" "server/log"
"server/torr" "server/torr"
@@ -51,6 +53,9 @@ func Start(port string) {
api.SetupRoute(&route.RouterGroup) api.SetupRoute(&route.RouterGroup)
pages.SetupRoute(&route.RouterGroup) pages.SetupRoute(&route.RouterGroup)
} }
if settings.BTsets.EnableDLNA {
dlna.Start()
}
log.TLogln("Start web server at port", port) log.TLogln("Start web server at port", port)
waitChan <- route.Run(":" + port) waitChan <- route.Run(":" + port)
} }
@@ -60,6 +65,7 @@ func Wait() error {
} }
func Stop() { func Stop() {
dlna.Stop()
BTS.Disconnect() BTS.Disconnect()
waitChan <- nil waitChan <- nil
} }

View File

@@ -67,7 +67,10 @@ export default function AddDialog({
const allHashes = torrents.map(({ hash }) => hash) const allHashes = torrents.map(({ hash }) => hash)
allHashes.includes(currentSourceHash) && handleClose() allHashes.includes(currentSourceHash) && handleClose()
}, [isSaving, torrents, currentSourceHash, handleClose]) // FIXME! check api reply on add links
const linkRegex = /^(http(s?)):\/\/.*/i
torrentSource.match(linkRegex) !== null && handleClose()
}, [isSaving, torrents, torrentSource, currentSourceHash, handleClose])
const fullScreen = useMediaQuery('@media (max-width:930px)') const fullScreen = useMediaQuery('@media (max-width:930px)')

View File

@@ -95,8 +95,16 @@ export default function App() {
)} )}
</HeaderToggle> </HeaderToggle>
<HeaderToggle onClick={() => (currentLang === 'en' ? changeLang('ru') : changeLang('en'))}> <HeaderToggle
{currentLang === 'en' ? 'EN' : 'RU'} onClick={() =>
currentLang === 'en'
? changeLang('ru')
: currentLang === 'ru'
? changeLang('ua')
: changeLang('en')
}
>
{currentLang.toUpperCase()}
</HeaderToggle> </HeaderToggle>
</div> </div>
</AppHeader> </AppHeader>

View File

@@ -1,11 +1,11 @@
import styled, { css } from 'styled-components' import styled, { css } from 'styled-components'
const viewedPrimaryColor = '#bdbdbd' const viewedPrimaryColor = '#858c90'
const viewedSecondaryColor = '#c4c4c4' const viewedSecondaryColor = '#8c9498'
const viewedTertiaryColor = '#c9c9c9' const viewedTertiaryColor = '#949ca0'
const bigTableDividerColor = '#ddd' const bigTableDividerColor = '#d2d2d2'
const bigTableDefaultRowColor = '#fff' const bigTableDefaultRowColor = '#f3f3f3'
const bigTableViewedRowColor = '#f3f3f3' const bigTableViewedRowColor = '#ddd'
const viewedIndicator = css` const viewedIndicator = css`
${({ ${({
@@ -187,7 +187,7 @@ export const ShortTable = styled.div`
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
align-items: center; align-items: center;
gap: 20px; gap: 20px;
background: #fff; background: #f3f3f3;
@media (max-width: 410px) { @media (max-width: 410px) {
gap: 10px; gap: 10px;

View File

@@ -93,7 +93,7 @@ const TorrentCache = ({ cache, isMini, isSnakeDebugMode }) => {
if (isSnakeDebugMode && priority > 0) { if (isSnakeDebugMode && priority > 0) {
let info = '' let info = ''
if (priority === 1) info = '*' if (priority === 1) info = ''
else if (priority === 2) info = 'H' else if (priority === 2) info = 'H'
else if (priority === 3) info = 'R' else if (priority === 3) info = 'R'
else if (priority === 4) info = 'N' else if (priority === 4) info = 'N'

View File

@@ -7,10 +7,10 @@ export const snakeSettings = {
borderWidth: 1, borderWidth: 1,
pieceSize: 14, pieceSize: 14,
gapBetweenPieces: 3, gapBetweenPieces: 3,
borderColor: rgba('#949ca0', 0.25), borderColor: rgba('#fff', 0.2),
completeColor: rgba(mainColors.dark.primary, 0.5), completeColor: rgba(mainColors.dark.primary, 0.5),
backgroundColor: '#f1eff3', backgroundColor: '#949ca0',
progressColor: mainColors.dark.secondary, progressColor: rgba('#fff', 0.2),
readerColor: '#8f0405', readerColor: '#8f0405',
rangeColor: '#cda184', rangeColor: '#cda184',
}, },

View File

@@ -28,13 +28,16 @@ const TorrentFunctions = memo(
<> <>
<SmallLabel>{t('DownloadPlaylist')}</SmallLabel> <SmallLabel>{t('DownloadPlaylist')}</SmallLabel>
<SectionSubName mb={10}> <SectionSubName mb={10}>
<strong>{t('LatestFilePlayed')}</strong> {latestViewedFileData?.title}. {t('LatestFilePlayed')}{' '}
<strong>
{latestViewedFileData?.title}.
{latestViewedFileData?.season && ( {latestViewedFileData?.season && (
<> <>
{' '} {' '}
{t('Season')}: {latestViewedFileData?.season}. {t('Episode')}: {latestViewedFileData?.episode}. {t('Season')}: {latestViewedFileData?.season}. {t('Episode')}: {latestViewedFileData?.episode}.
</> </>
)} )}
</strong>
</SectionSubName> </SectionSubName>
<MainSectionButtonGroup> <MainSectionButtonGroup>

View File

@@ -289,7 +289,7 @@ export const LoadingProgress = styled.div.attrs(
return { return {
// this block is here according to styled-components recomendation about fast changable components // this block is here according to styled-components recomendation about fast changable components
style: { style: {
background: `linear-gradient(to right, ${gradientStartColor} 0%, ${gradientEndColor} ${percentage}%, #fff ${percentage}%, #fff 100%)`, background: `linear-gradient(to right, ${gradientStartColor} 0%, ${gradientEndColor} ${percentage}%, #eee ${percentage}%, #fff 100%)`,
}, },
} }
}, },

View File

@@ -10,6 +10,7 @@ export default function SecondarySettingsComponent({ settings, inputForm }) {
const { const {
RetrackersMode, RetrackersMode,
TorrentDisconnectTimeout, TorrentDisconnectTimeout,
EnableDLNA,
EnableIPv6, EnableIPv6,
ForceEncrypt, ForceEncrypt,
DisableTCP, DisableTCP,
@@ -133,6 +134,11 @@ export default function SecondarySettingsComponent({ settings, inputForm }) {
label='UPnP (Universal Plug and Play)' label='UPnP (Universal Plug and Play)'
labelPlacement='start' labelPlacement='start'
/> />
<FormControlLabel
control={<Switch checked={EnableDLNA} onChange={inputForm} id='EnableDLNA' color='secondary' />}
label={t('SettingsDialog.DLNA')}
labelPlacement='start'
/>
<br /> <br />
<InputLabel htmlFor='RetrackersMode'>{t('SettingsDialog.RetrackersMode')}</InputLabel> <InputLabel htmlFor='RetrackersMode'>{t('SettingsDialog.RetrackersMode')}</InputLabel>
<Select <Select

View File

@@ -3,6 +3,7 @@ import { initReactI18next } from 'react-i18next'
import LanguageDetector from 'i18next-browser-languagedetector' import LanguageDetector from 'i18next-browser-languagedetector'
import translationEN from 'locales/en/translation.json' import translationEN from 'locales/en/translation.json'
import translationRU from 'locales/ru/translation.json' import translationRU from 'locales/ru/translation.json'
import translationUA from 'locales/ua/translation.json'
i18n i18n
.use(LanguageDetector) .use(LanguageDetector)
@@ -10,7 +11,11 @@ i18n
.init({ .init({
fallbackLng: 'en', // default language will be used if none of declared lanuages detected (en, ru) fallbackLng: 'en', // default language will be used if none of declared lanuages detected (en, ru)
interpolation: { escapeValue: false }, // react already safes from xss interpolation: { escapeValue: false }, // react already safes from xss
resources: { en: { translation: translationEN }, ru: { translation: translationRU } }, resources: {
en: { translation: translationEN },
ru: { translation: translationRU },
ua: { translation: translationUA },
},
}) })
export default i18n export default i18n

View File

@@ -33,12 +33,12 @@
"CopyHash": "Copy Hash", "CopyHash": "Copy Hash",
"CopyLink": "Copy link", "CopyLink": "Copy link",
"Data": "Data", "Data": "Data",
"DebugMode": "Show download priorities", "DebugMode": "Download priorities",
"Delete": "Delete", "Delete": "Delete",
"DeleteTorrent?": "Delete Torrent?", "DeleteTorrent?": "Delete Torrent?",
"DeleteTorrents?": "Delete All Torrents?", "DeleteTorrents?": "Delete All Torrents?",
"DetailedCacheView": { "DetailedCacheView": {
"button": "Detailed Cache View", "button": "Cache Details View",
"header": "$t(DetailedCacheView.button)" "header": "$t(DetailedCacheView.button)"
}, },
"Details": "Details", "Details": "Details",
@@ -98,6 +98,7 @@
"DHT": "DHT (Distributed Hash Table)", "DHT": "DHT (Distributed Hash Table)",
"DhtConnectionLimit": "DHT Connection Limit", "DhtConnectionLimit": "DHT Connection Limit",
"Disk": "Disk", "Disk": "Disk",
"DLNA": "DLNA Media Server",
"DontAddRetrackers": "Don`t add retrackers", "DontAddRetrackers": "Don`t add retrackers",
"DownloadRateLimit": "Download Rate Limit", "DownloadRateLimit": "Download Rate Limit",
"ForceEncrypt": "Force Encrypt Headers", "ForceEncrypt": "Force Encrypt Headers",

View File

@@ -33,13 +33,13 @@
"CopyHash": "Скопировать хеш", "CopyHash": "Скопировать хеш",
"CopyLink": "Копировать", "CopyLink": "Копировать",
"Data": "Данные", "Data": "Данные",
"DebugMode": "Метки приоритетов загрузки", "DebugMode": "Метки приоритетов",
"Delete": "Удалить", "Delete": "Удалить",
"DeleteTorrent?": "Удалить торрент?", "DeleteTorrent?": "Удалить торрент?",
"DeleteTorrents?": "Удалить все торренты?", "DeleteTorrents?": "Удалить все торренты?",
"DetailedCacheView": { "DetailedCacheView": {
"button": "Информация о заполнении кеша", "button": "Заполнение кеша",
"header": "Заполнение кеша" "header": "Информация о кеше"
}, },
"Details": "Инфо", "Details": "Инфо",
"Donate?": "Хотите поддержать проект?", "Donate?": "Хотите поддержать проект?",
@@ -98,6 +98,7 @@
"DHT": "DHT (Distributed Hash Table)", "DHT": "DHT (Distributed Hash Table)",
"DhtConnectionLimit": "Лимит подключений DHT", "DhtConnectionLimit": "Лимит подключений DHT",
"Disk": "ПЗУ / Накопитель", "Disk": "ПЗУ / Накопитель",
"DLNA": "DLNA-медиасервер",
"DontAddRetrackers": "Ничего не делать", "DontAddRetrackers": "Ничего не делать",
"DownloadRateLimit": "Ограничение скорости загрузки", "DownloadRateLimit": "Ограничение скорости загрузки",
"ForceEncrypt": "Принудительное шифрование заголовков", "ForceEncrypt": "Принудительное шифрование заголовков",

View File

@@ -0,0 +1,151 @@
{
"About": "Про сервер",
"Actions": "Дії",
"Add": "Додати",
"AddDialog": {
"AddPosterLinkInput": "Посилання на плакат",
"AddTorrentSourceNotification": "Спочатку додайте torrent-джерело",
"AppendFile": {
"Or": "ЧИ",
"ClickOrDrag": "НАТИСНІТЬ / ПЕРЕТЯГНІТЬ ФАЙЛ (.torrent)"
},
"CustomTorrentTitle": "Власна назва (опційно)",
"CustomTorrentTitleHelperText": "Напишіть власну назву, щоб знайти плакат",
"HashExists": "Даний торент вже є у базі даних",
"OriginalTorrentTitle": "Оригінальна назва торенту",
"TitleBlank": "Назва (порожнє - ориг. назва торенту)",
"TorrentSourceLink": "Посилання на джерело терента",
"TorrentSourceOptions": "magnet-посилання / хеш / посилання на .torrent файл",
"WrongTorrentSource": "Хибне torrent-джерело"
},
"AddFromLink": "Додати торент",
"AddNewTorrent": "Додати новий торент",
"B": "Б",
"bps": "біт/c",
"Buffer": "Буфер",
"BufferNote": "Встановіть буфер попереднього завантаження > 32 МБ в налаштуваннях, щоб його змінити.",
"Cache": "Кеш",
"Cancel": "Скасувати",
"Clear": "Очистити",
"Close": "Закрити",
"CloseServer?": "Хочете вимкнути сервер?",
"CloseServer": "Вимк. сервер",
"CopyHash": "Скопіювати хеш",
"CopyLink": "Копіювати",
"Data": "Дані",
"DebugMode": "Мітки пріоритетів",
"Delete": "Видалити",
"DeleteTorrent?": "Видалити торент?",
"DeleteTorrents?": "Видалити всі торенти?",
"DetailedCacheView": {
"button": "Заповнення кеша",
"header": "Інформація про кеш"
},
"Details": "Деталі",
"Donate?": "Бажаєте підтримати проєкт?",
"Donate": "Підтримка",
"DownloadPlaylist": "Завантажити список відтворення",
"DownloadSpeed": "Швидкість завантаження",
"Drop": "Скинути",
"DropTorrent": "Скинути торент",
"Edit": "Редагувати",
"EditTorrent": "Редагувати торент",
"Episode": "Серія",
"FromLatestFile": "З останнього файлу",
"Full": "Повний",
"GB": "ГБ",
"Gbps": "Гбіт/c",
"Host": "Хост",
"Info": "Інфо",
"KB": "КБ",
"kbps": "кбіт/с",
"Kilobytes": "Кілобайт",
"LatestFilePlayed": "Останній файл, що програвався:",
"Links": "Посилання",
"MB": "МБ",
"Mbps": "Мбіт/c",
"Name": "Назва",
"NoTorrentsAdded": "Немає торентів",
"Offline": "Сервер не доступний",
"OK": "OK",
"OpenLink": "Відкрити",
"Peers": "Піри",
"PiecesCount": "К-сть блоків",
"PiecesLength": "Розмір блоку",
"Playlist": "Плейлист",
"Preload": "Передзав.",
"ProjectSource": "Сайт проекту",
"Releases": "Релізи TorrServer",
"RemoveAll": "Видалити все",
"RemoveViews": "Видалити перегляди",
"Resolution": "Дозволи",
"Save": "Зберегти",
"ScrollDown": "прокрутіть вних",
"Season": "Сезон",
"Sec": "c",
"Seconds": "Секунди",
"SelectSeason": "Вибір сезону",
"SettingsDialog": {
"AddRetrackers": "Додавати",
"AdditionalSettings": "Додаткові налаштування",
"CacheBeforeReaderDesc": "з кешу буде збережено до поточного відтворюваного кадру",
"CacheAfterReaderDesc": "з кешу буде завантажено після поточно відтвореного кадру",
"CacheSize": "Размір кешу",
"CacheSettings": "Налаштування кешу",
"CacheStorageLocation": "Місце збереження кешу",
"ConnectionsLimit": "Обмеження з'єдань",
"ConnectionsLimitHint": "рекомендовано 20-25",
"DHT": "DHT (Distributed Hash Table)",
"DhtConnectionLimit": "Обмеження з'єдань DHT",
"Disk": "ПЗП / Носій",
"DLNA": "DLNA-медиасервер",
"DontAddRetrackers": "Нічого не робити",
"DownloadRateLimit": "Обмеження швидкості завантаження",
"ForceEncrypt": "Примусово шифрувати заголовки",
"PeersListenPort": "Порт для вхідних з'єднань",
"PeersListenPortHint": "1024 - 65535, 0 - авто",
"PreloadCache": "Буфер попер. завантаження",
"ProMode": "ПРО-режим",
"RAM": "Оперативна пам'ять",
"ReaderReadAHead": "Качати кеш зазделегідь (5-100%, рек. 95%)",
"RemoveCacheOnDrop": "Видаляти кеш при відключенні від торрента",
"RemoveCacheOnDropDesc": "Якщо виключено, тоді кеш видаляється при видалені торенту.",
"RemoveRetrackers": "Видалити",
"ReplaceRetrackers": "Замінити",
"RetrackersMode": "Ретрекери",
"ResetToDefault": "Базові налаштування",
"Settings": "Налаштування",
"TorrentDisconnectTimeout": "Час очікування відключення торрента",
"TorrentsSavePath": "Шлях для збереження кешу",
"Upload": "Відвантаження (не рекомендується вимикати)",
"UploadRateLimit": "Обмеження швидкості відвантаження",
"UseDiskDesc": "Краще використовуйте оперативну пам'ять або зовнішню пам'ять на пристроях на основі flash-пам'яттю",
"Tabs": {
"Main": "Основні",
"Additional": "Додаткові",
"AdditionalDisabled": "(включіть ПРО-режим)"
}
},
"Size": "Розмір",
"SpecialThanks": "Окрема подяка",
"Speed": "Швидкість",
"Support": "Підтримати",
"TB": "ТБ",
"Tbps": "Тбіт/с",
"ThanksToEveryone": "Дякуємо всім, хто тестував і допомагав!",
"TorrentAdded": "Доданий",
"TorrentClosed": "Закритий",
"TorrentContent": "Вміст торенту",
"TorrentDetails": "Інформація про торент",
"TorrentGettingInfo": "Отримання інформації",
"TorrentInDb": "Торент в БД",
"TorrentPreload": "Передзавантаження",
"TorrentSize": "Розмір торенту",
"TorrentState": "Дані торенту",
"TorrentStatus": "Статус торенту",
"TorrentWorking": "Активний",
"TurnOff": "Виключити",
"UploadFile": "Завантажити файл",
"UploadSpeed": "Швидкість відвантаження",
"Viewed": "Перегл."
}

View File

@@ -78,7 +78,7 @@ export const themeColors = {
detailedView: { detailedView: {
gradientStartColor: '#656f76', gradientStartColor: '#656f76',
gradientEndColor: '#545a5e', gradientEndColor: '#545a5e',
cacheSectionBGColor: '#dee3e5', cacheSectionBGColor: '#949ca0',
}, },
addDialog: { addDialog: {
gradientStartColor: '#656f76', gradientStartColor: '#656f76',

File diff suppressed because it is too large Load Diff