diff --git a/server/dlna/dlna.go b/server/dlna/dlna.go new file mode 100644 index 0000000..9129c31 --- /dev/null +++ b/server/dlna/dlna.go @@ -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 +} diff --git a/server/dlna/list.go b/server/dlna/list.go new file mode 100644 index 0000000..c15c70f --- /dev/null +++ b/server/dlna/list.go @@ -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 +} diff --git a/server/dlna/utils.go b/server/dlna/utils.go new file mode 100644 index 0000000..decf282 --- /dev/null +++ b/server/dlna/utils.go @@ -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 +} diff --git a/server/go.mod b/server/go.mod index 2802f01..f3f1d3f 100644 --- a/server/go.mod +++ b/server/go.mod @@ -2,8 +2,15 @@ module server 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 ( 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/torrent v1.30.4 github.com/gin-contrib/cors v1.3.1 @@ -22,8 +29,7 @@ require ( github.com/anacrolix/chansync v0.1.0 // indirect github.com/anacrolix/confluence v1.8.0 // indirect github.com/anacrolix/dht/v2 v2.10.3 // indirect - github.com/anacrolix/envpprof v1.1.1 // indirect - github.com/anacrolix/go-libutp v1.0.4 // indirect + github.com/anacrolix/ffprobe v1.0.0 // indirect github.com/anacrolix/log v0.9.0 // indirect github.com/anacrolix/missinggo/perf v1.0.0 // indirect github.com/anacrolix/missinggo/v2 v2.5.2 // indirect diff --git a/server/go.sum b/server/go.sum index febdaf1..739e451 100644 --- a/server/go.sum +++ b/server/go.sum @@ -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.1 h1:sHQCyj7HtiSfaZAzL2rJrQdyS7odLqlwO6nhk/tG/j8= 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 v1.0.2/go.mod h1:uIH0A72V++j0D1nnmTjjZUiH/ujPkFxYWkxQ02+7S0U= 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/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/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.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= 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/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8= 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= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 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-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-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-20210427231257-85d9c07bbe3a/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 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-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-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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/server/server.go b/server/server.go index 9a4b20d..b9ebab8 100644 --- a/server/server.go +++ b/server/server.go @@ -25,8 +25,9 @@ func Start(port string, roSets bool) { log.TLogln("Port", port, "already in use! Abort") os.Exit(1) } else { - go cleanCache() - web.Start(port) + go cleanCache() + settings.Port = port + web.Start(port) } } diff --git a/server/settings/btsets.go b/server/settings/btsets.go index d62c762..49a3f08 100644 --- a/server/settings/btsets.go +++ b/server/settings/btsets.go @@ -27,6 +27,9 @@ type BTSets struct { TorrentDisconnectTimeout int // in seconds EnableDebug bool // print logs + // DLNA + EnableDLNA bool + // BT Config EnableIPv6 bool DisableTCP bool @@ -38,7 +41,7 @@ type BTSets struct { DownloadRateLimit int // in kb, 0 - inf UploadRateLimit int // in kb, 0 - inf ConnectionsLimit int - PeersListenPort int + PeersListenPort int } func (v *BTSets) String() string { diff --git a/server/settings/settings.go b/server/settings/settings.go index bdff98a..a08693a 100644 --- a/server/settings/settings.go +++ b/server/settings/settings.go @@ -10,6 +10,7 @@ import ( var ( tdb *TDB Path string + Port string ReadOnly bool HttpAuth bool ) diff --git a/server/torr/apihelper.go b/server/torr/apihelper.go index 1eb3782..773b609 100644 --- a/server/torr/apihelper.go +++ b/server/torr/apihelper.go @@ -101,7 +101,7 @@ func GetTorrent(hashHex string) *Torrent { go func() { lockApi.Lock() defer lockApi.Unlock() - log.TLogln("Add torrent") + log.TLogln("New torrent", tor.Hash()) tr, _ := NewTorrent(tor.TorrentSpec, bts) if tr != nil { tr.Title = tor.Title diff --git a/server/torr/btserver.go b/server/torr/btserver.go index fa6ca23..21e6cf7 100644 --- a/server/torr/btserver.go +++ b/server/torr/btserver.go @@ -79,6 +79,7 @@ func (bt *BTServer) configure() { bt.config.HTTPUserAgent = userAgent bt.config.ExtendedHandshakeClientVersion = cliVers bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit + bt.config.TotalHalfOpenConns = 500 // Encryption/Obfuscation bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{ RequirePreferred: settings.BTsets.ForceEncrypt, diff --git a/server/web/api/settings.go b/server/web/api/settings.go index 0269dcc..afdeb30 100644 --- a/server/web/api/settings.go +++ b/server/web/api/settings.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/pkg/errors" + "server/dlna" sets "server/settings" "server/torr" @@ -29,10 +30,15 @@ func settings(c *gin.Context) { return } else if req.Action == "set" { torr.SetSettings(req.Sets) + dlna.Stop() + if req.Sets.EnableDLNA { + dlna.Start() + } c.Status(200) return } else if req.Action == "def" { torr.SetDefSettings() + dlna.Stop() c.Status(200) return } diff --git a/server/web/server.go b/server/web/server.go index 2e655c4..6aefd27 100644 --- a/server/web/server.go +++ b/server/web/server.go @@ -6,6 +6,8 @@ import ( "github.com/gin-contrib/cors" "github.com/gin-contrib/location" "github.com/gin-gonic/gin" + "server/dlna" + "server/settings" "server/log" "server/torr" @@ -51,6 +53,9 @@ func Start(port string) { api.SetupRoute(&route.RouterGroup) pages.SetupRoute(&route.RouterGroup) } + if settings.BTsets.EnableDLNA { + dlna.Start() + } log.TLogln("Start web server at port", port) waitChan <- route.Run(":" + port) } @@ -60,6 +65,7 @@ func Wait() error { } func Stop() { + dlna.Stop() BTS.Disconnect() waitChan <- nil } diff --git a/web/src/components/Add/AddDialog.jsx b/web/src/components/Add/AddDialog.jsx index f5649a8..01e146f 100644 --- a/web/src/components/Add/AddDialog.jsx +++ b/web/src/components/Add/AddDialog.jsx @@ -67,7 +67,10 @@ export default function AddDialog({ const allHashes = torrents.map(({ hash }) => hash) 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)') diff --git a/web/src/components/App/index.jsx b/web/src/components/App/index.jsx index b0bd0c0..cbee0c9 100644 --- a/web/src/components/App/index.jsx +++ b/web/src/components/App/index.jsx @@ -95,8 +95,16 @@ export default function App() { )} - (currentLang === 'en' ? changeLang('ru') : changeLang('en'))}> - {currentLang === 'en' ? 'EN' : 'RU'} + + currentLang === 'en' + ? changeLang('ru') + : currentLang === 'ru' + ? changeLang('ua') + : changeLang('en') + } + > + {currentLang.toUpperCase()} diff --git a/web/src/components/DialogTorrentDetailsContent/Table/style.js b/web/src/components/DialogTorrentDetailsContent/Table/style.js index a9079c4..1e766f4 100644 --- a/web/src/components/DialogTorrentDetailsContent/Table/style.js +++ b/web/src/components/DialogTorrentDetailsContent/Table/style.js @@ -1,11 +1,11 @@ import styled, { css } from 'styled-components' -const viewedPrimaryColor = '#bdbdbd' -const viewedSecondaryColor = '#c4c4c4' -const viewedTertiaryColor = '#c9c9c9' -const bigTableDividerColor = '#ddd' -const bigTableDefaultRowColor = '#fff' -const bigTableViewedRowColor = '#f3f3f3' +const viewedPrimaryColor = '#858c90' +const viewedSecondaryColor = '#8c9498' +const viewedTertiaryColor = '#949ca0' +const bigTableDividerColor = '#d2d2d2' +const bigTableDefaultRowColor = '#f3f3f3' +const bigTableViewedRowColor = '#ddd' const viewedIndicator = css` ${({ @@ -187,7 +187,7 @@ export const ShortTable = styled.div` grid-template-columns: repeat(3, 1fr); align-items: center; gap: 20px; - background: #fff; + background: #f3f3f3; @media (max-width: 410px) { gap: 10px; diff --git a/web/src/components/DialogTorrentDetailsContent/TorrentCache/index.jsx b/web/src/components/DialogTorrentDetailsContent/TorrentCache/index.jsx index 847cb70..76b2d88 100644 --- a/web/src/components/DialogTorrentDetailsContent/TorrentCache/index.jsx +++ b/web/src/components/DialogTorrentDetailsContent/TorrentCache/index.jsx @@ -93,7 +93,7 @@ const TorrentCache = ({ cache, isMini, isSnakeDebugMode }) => { if (isSnakeDebugMode && priority > 0) { let info = '' - if (priority === 1) info = '*' + if (priority === 1) info = '' else if (priority === 2) info = 'H' else if (priority === 3) info = 'R' else if (priority === 4) info = 'N' diff --git a/web/src/components/DialogTorrentDetailsContent/TorrentCache/snakeSettings.js b/web/src/components/DialogTorrentDetailsContent/TorrentCache/snakeSettings.js index fcc1d7a..55d99bd 100644 --- a/web/src/components/DialogTorrentDetailsContent/TorrentCache/snakeSettings.js +++ b/web/src/components/DialogTorrentDetailsContent/TorrentCache/snakeSettings.js @@ -7,10 +7,10 @@ export const snakeSettings = { borderWidth: 1, pieceSize: 14, gapBetweenPieces: 3, - borderColor: rgba('#949ca0', 0.25), + borderColor: rgba('#fff', 0.2), completeColor: rgba(mainColors.dark.primary, 0.5), - backgroundColor: '#f1eff3', - progressColor: mainColors.dark.secondary, + backgroundColor: '#949ca0', + progressColor: rgba('#fff', 0.2), readerColor: '#8f0405', rangeColor: '#cda184', }, diff --git a/web/src/components/DialogTorrentDetailsContent/TorrentFunctions/index.jsx b/web/src/components/DialogTorrentDetailsContent/TorrentFunctions/index.jsx index ba2f9c4..f5aeebc 100644 --- a/web/src/components/DialogTorrentDetailsContent/TorrentFunctions/index.jsx +++ b/web/src/components/DialogTorrentDetailsContent/TorrentFunctions/index.jsx @@ -28,13 +28,16 @@ const TorrentFunctions = memo( <> {t('DownloadPlaylist')} - {t('LatestFilePlayed')} {latestViewedFileData?.title}. - {latestViewedFileData?.season && ( - <> - {' '} - {t('Season')}: {latestViewedFileData?.season}. {t('Episode')}: {latestViewedFileData?.episode}. - - )} + {t('LatestFilePlayed')}{' '} + + {latestViewedFileData?.title}. + {latestViewedFileData?.season && ( + <> + {' '} + {t('Season')}: {latestViewedFileData?.season}. {t('Episode')}: {latestViewedFileData?.episode}. + + )} + diff --git a/web/src/components/DialogTorrentDetailsContent/style.js b/web/src/components/DialogTorrentDetailsContent/style.js index 7b1eca3..e3f7d09 100644 --- a/web/src/components/DialogTorrentDetailsContent/style.js +++ b/web/src/components/DialogTorrentDetailsContent/style.js @@ -289,7 +289,7 @@ export const LoadingProgress = styled.div.attrs( return { // this block is here according to styled-components recomendation about fast changable components 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%)`, }, } }, diff --git a/web/src/components/Settings/SecondarySettingsComponent.jsx b/web/src/components/Settings/SecondarySettingsComponent.jsx index 1149713..8f977a7 100644 --- a/web/src/components/Settings/SecondarySettingsComponent.jsx +++ b/web/src/components/Settings/SecondarySettingsComponent.jsx @@ -10,6 +10,7 @@ export default function SecondarySettingsComponent({ settings, inputForm }) { const { RetrackersMode, TorrentDisconnectTimeout, + EnableDLNA, EnableIPv6, ForceEncrypt, DisableTCP, @@ -133,6 +134,11 @@ export default function SecondarySettingsComponent({ settings, inputForm }) { label='UPnP (Universal Plug and Play)' labelPlacement='start' /> + } + label={t('SettingsDialog.DLNA')} + labelPlacement='start' + />
{t('SettingsDialog.RetrackersMode')}