mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
Merge branch 'master' into 230-torrents-category
This commit is contained in:
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. Linux Ubuntu 22.04]
|
||||||
|
- TorrServer Version [e.g. MatriX.129]
|
||||||
|
|
||||||
|
**Smartphone or tvbox on Android (please complete the following information):**
|
||||||
|
- Device: [e.g. Ugoos am6]
|
||||||
|
- OS: [e.g. Android 9]
|
||||||
|
- TorrServer Version [e.g. MatriX.129]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: "[Feature]"
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
43
README.md
43
README.md
@@ -62,10 +62,10 @@ curl -s https://raw.githubusercontent.com/YouROK/TorrServer/master/installTorrSe
|
|||||||
|
|
||||||
#### macOS
|
#### macOS
|
||||||
|
|
||||||
Run in console
|
Run in Terminal.app
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s https://raw.githubusercontent.com/YouROK/TorrServer/master/installTorrServerMac.sh -o installTorrserverMac.sh && chmod 755 installTorrServerMac.sh && sudo ./installTorrServerMac.sh
|
curl -s https://raw.githubusercontent.com/YouROK/TorrServer/master/installTorrServerMac.sh -o installTorrserverMac.sh && chmod 755 installTorrServerMac.sh && bash ./installTorrServerMac.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternative install script for Intel Macs: <https://github.com/dancheskus/TorrServerMacInstaller>
|
Alternative install script for Intel Macs: <https://github.com/dancheskus/TorrServerMacInstaller>
|
||||||
@@ -81,12 +81,12 @@ On FreeBSD (TrueNAS/FreeNAS) you can use this plugin: <https://github.com/filka9
|
|||||||
|
|
||||||
### Server args
|
### Server args
|
||||||
|
|
||||||
- `--port PORT`, `-p PORT` - web server port, default 8090
|
- `--port PORT`, `-p PORT` - web server port (default 8090)
|
||||||
- `--ssl` - enables https for web server
|
- `--ssl` - enables https for web server
|
||||||
- `--sslport PORT` - web server https port, default 8091. If not set, will be taken from db (if stored previously) or use default.
|
- `--sslport PORT` - web server https port (default 8091). If not set, will be taken from db (if stored previously) or the default will be used.
|
||||||
- `--sslcert PATH` - path to ssl cert file. If not set, will be taken from db (if stored previously) or default self-signed certificate/key will be generated.
|
- `--sslcert PATH` - path to ssl cert file. If not set, will be taken from db (if stored previously) or default self-signed certificate/key will be generated.
|
||||||
- `--sslkey PATH` - path to ssl key file. If not set, will be taken from db (if stored previously) or default self-signed certificate/key will be generated.
|
- `--sslkey PATH` - path to ssl key file. If not set, will be taken from db (if stored previously) or default self-signed certificate/key will be generated.
|
||||||
- `--path PATH`, `-d PATH` - database dir path
|
- `--path PATH`, `-d PATH` - database and config dir path
|
||||||
- `--logpath LOGPATH`, `-l LOGPATH` - server log file path
|
- `--logpath LOGPATH`, `-l LOGPATH` - server log file path
|
||||||
- `--weblogpath WEBLOGPATH`, `-w WEBLOGPATH` - web access log file path
|
- `--weblogpath WEBLOGPATH`, `-w WEBLOGPATH` - web access log file path
|
||||||
- `--rdb`, `-r` - start in read-only DB mode
|
- `--rdb`, `-r` - start in read-only DB mode
|
||||||
@@ -171,7 +171,7 @@ Synology NAS packages repo source: https://grigi.lt
|
|||||||
|
|
||||||
#### Server
|
#### Server
|
||||||
|
|
||||||
- Install [Golang](https://golang.org/doc/install) 1.18+
|
- Install [Golang](https://golang.org/doc/install) 1.20+
|
||||||
- Go to the TorrServer source directory
|
- Go to the TorrServer source directory
|
||||||
- Run build script under linux or macOS `build-all.sh`
|
- Run build script under linux or macOS `build-all.sh`
|
||||||
|
|
||||||
@@ -245,23 +245,26 @@ local:127.0.0.1
|
|||||||
|
|
||||||
- [QIWI](https://qiwi.com/n/YOUROK85)
|
- [QIWI](https://qiwi.com/n/YOUROK85)
|
||||||
- [YooMoney](https://yoomoney.ru/to/410013733697114/200)
|
- [YooMoney](https://yoomoney.ru/to/410013733697114/200)
|
||||||
- [PayPal](https://www.paypal.me/yourok)
|
|
||||||
- SberBank Card: **5484 4000 2285 7839**
|
- SberBank Card: **5484 4000 2285 7839**
|
||||||
- YooMoney Card: **4048 4150 1812 8179**
|
|
||||||
|
|
||||||
## Thanks to everyone who tested and helped
|
## Thanks to everyone who tested and helped
|
||||||
|
|
||||||
- [anacrolix (Matt Joiner)](https://github.com/anacrolix)
|
- [anacrolix](https://github.com/anacrolix) Matt Joiner
|
||||||
- [tsynik](https://github.com/tsynik)
|
- [tsynik](https://github.com/tsynik)
|
||||||
- [dancheskus](https://github.com/dancheskus)
|
- [dancheskus](https://github.com/dancheskus) for react web GUI and PWA code
|
||||||
- [kolsys](https://github.com/kolsys)
|
- [kolsys](https://github.com/kolsys) for initial Media Station X support
|
||||||
- [vladlenas](https://github.com/vladlenas)
|
- [damiva](https://github.com/damiva) for Media Station X code updates
|
||||||
- [Nemiroff (Tw1cker)](https://github.com/Nemiroff)
|
- [vladlenas](https://github.com/vladlenas) for NAS builds
|
||||||
- [spawnlmg (SpAwN_LMG)](https://github.com/spawnlmg)
|
- [Nemiroff](https://github.com/Nemiroff) Tw1cker
|
||||||
- [TopperBG (Dimitar Maznekov)](https://github.com/TopperBG)
|
- [spawnlmg](https://github.com/spawnlmg) SpAwN_LMG for testing
|
||||||
- [FaintGhost (Zhang Yaowei)](https://github.com/FaintGhost)
|
- [TopperBG](https://github.com/TopperBG) Dimitar Maznekov for Bulgarian web translation
|
||||||
- [Anton111111 (Anton Potekhin)](https://github.com/Anton111111)
|
- [FaintGhost](https://github.com/FaintGhost) Zhang Yaowei for Simplified Chinese web translation
|
||||||
- [lieranderl (Evgeni)](https://github.com/lieranderl)
|
- [Anton111111](https://github.com/Anton111111) Anton Potekhin for sleep on Windows fixes
|
||||||
- [cocool97](https://github.com/cocool97)
|
- [lieranderl](https://github.com/lieranderl) Evgeni for adding SSL support code
|
||||||
- [shadeov](https://github.com/shadeov)
|
- [cocool97](https://github.com/cocool97) for openapi API documentation
|
||||||
|
- [shadeov](https://github.com/shadeov) for README improvements
|
||||||
|
- [butaford](https://github.com/butaford) Pavel for make docker file and scripts
|
||||||
|
- [filimonic](https://github.com/filimonic) Alexey D. Filimonov
|
||||||
|
- [leporel](https://github.com/leporel) Viacheslav Evseev
|
||||||
- and others
|
- and others
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ echo "Build web"
|
|||||||
export NODE_OPTIONS=--openssl-legacy-provider
|
export NODE_OPTIONS=--openssl-legacy-provider
|
||||||
$GOBIN run gen_web.go
|
$GOBIN run gen_web.go
|
||||||
|
|
||||||
|
#### Update api docs
|
||||||
|
echo "Build docs"
|
||||||
|
$GOBIN install github.com/swaggo/swag/cmd/swag@latest
|
||||||
|
cd "${ROOT}/server" || exit 1
|
||||||
|
swag init -g web/server.go
|
||||||
|
|
||||||
#### Build server
|
#### Build server
|
||||||
echo "Build server"
|
echo "Build server"
|
||||||
cd "${ROOT}/server" || exit 1
|
cd "${ROOT}/server" || exit 1
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
FLAGS="--path $TS_CONF_PATH --logpath $TS_LOG_PATH --port $TS_PORT --torrentsdir $TS_TORR_DIR"
|
FLAGS="--path $TS_CONF_PATH --logpath $TS_LOG_PATH --port $TS_PORT --torrentsdir $TS_TORR_DIR"
|
||||||
if [[ -n "$TS_HTTPAUTH" ]]; then FLAGS="${FLAGS} --httpauth"; fi
|
if [[ "$TS_HTTPAUTH" -eq 1 ]]; then FLAGS="${FLAGS} --httpauth"; fi
|
||||||
if [[ -n "$TS_RDB" ]]; then FLAGS="${FLAGS} --rdb"; fi
|
if [[ "$TS_RDB" -eq 1 ]]; then FLAGS="${FLAGS} --rdb"; fi
|
||||||
if [[ -n "$TS_DONTKILL" ]]; then FLAGS="${FLAGS} --dontkill"; fi
|
if [[ "$TS_DONTKILL" -eq 1 ]]; then FLAGS="${FLAGS} --dontkill"; fi
|
||||||
|
|
||||||
if [ ! -d $TS_CONF_PATH ]; then
|
if [ ! -d $TS_CONF_PATH ]; then
|
||||||
mkdir -p $TS_CONF_PATH
|
mkdir -p $TS_CONF_PATH
|
||||||
|
|||||||
6
docker/Dockerfile
Normal file
6
docker/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM alpine
|
||||||
|
LABEL maintainer "yourok"
|
||||||
|
RUN apk add --no-cache wget
|
||||||
|
COPY start.sh /start.sh
|
||||||
|
ENTRYPOINT /start.sh
|
||||||
|
|
||||||
86
docker/README.md
Normal file
86
docker/README.md
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
## TorrServer
|
||||||
|
|
||||||
|
After starting the container, the latest server is downloaded from GitHub.\
|
||||||
|
If you need update server to latest, repull container
|
||||||
|
|
||||||
|
Source code: https://github.com/YouROK/TorrServer
|
||||||
|
|
||||||
|
--------
|
||||||
|
|
||||||
|
Author of docker file and scripts [butaford (aka Pavel)](https://github.com/butaford)
|
||||||
|
|
||||||
|
--------
|
||||||
|
|
||||||
|
### Support platforms
|
||||||
|
* TorrServer-linux-386
|
||||||
|
* TorrServer-linux-amd64
|
||||||
|
* TorrServer-linux-arm5
|
||||||
|
* TorrServer-linux-arm64
|
||||||
|
* TorrServer-linux-arm7
|
||||||
|
|
||||||
|
--------
|
||||||
|
### Support env
|
||||||
|
TS_PORT: TS web port\
|
||||||
|
TS_PATH: config path and other\
|
||||||
|
TS_LOGPATHDIR: log path\
|
||||||
|
TS_LOGFILE: log file name\
|
||||||
|
TS_WEBLOGFILE: web log file name\
|
||||||
|
TS_RDB: read only config\
|
||||||
|
TS_HTTPAUTH: auth for server, accs.db should be in the TS_PATH\
|
||||||
|
TS_DONTKILL: don't kill server by signal\
|
||||||
|
TS_TORRENTSDIR: torrents listen directory\
|
||||||
|
TS_TORRENTADDR: torrents peer listen port\
|
||||||
|
TS_PUBIPV4: the IP addresses as our peers should see them. May differ from the local interfaces due to NAT or other network configurations\
|
||||||
|
TS_PUBIPV6: the IP addresses as our peers should see them. May differ from the local interfaces due to NAT or other network configurations\
|
||||||
|
TS_SEARCHWA: disable auth for search torrents if auth is enable
|
||||||
|
|
||||||
|
--------
|
||||||
|
### Docker run example
|
||||||
|
```
|
||||||
|
docker run -p 8090:8090 \
|
||||||
|
-e TS_PORT=8090 \
|
||||||
|
-e TS_PATH="/opt/torrserver/config" \
|
||||||
|
-e TS_LOGPATHDIR="/opt/torrserver/log/" \
|
||||||
|
-e TS_LOGFILE="ts.log" \
|
||||||
|
-e TS_WEBLOGFILE="tsweb.log" \
|
||||||
|
-e TS_RDB=true \
|
||||||
|
-e TS_HTTPAUTH=true \
|
||||||
|
-e TS_DONTKILL=true \
|
||||||
|
-e TS_TORRENTSDIR="/opt/torrserver/torrents" \
|
||||||
|
-e TS_TORRENTADDR=32000 \
|
||||||
|
-e TS_PUBIPV4=publicIP \
|
||||||
|
-e TS_PUBIPV6=publicIP \
|
||||||
|
-e TS_SEARCHWA=true \
|
||||||
|
yourok/torrserver
|
||||||
|
```
|
||||||
|
|
||||||
|
--------
|
||||||
|
### Docker compose example
|
||||||
|
```
|
||||||
|
version: '3.6'
|
||||||
|
services:
|
||||||
|
torrserver:
|
||||||
|
container_name: torrserver
|
||||||
|
image: yourok/torrserver
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- TS_PORT=8090
|
||||||
|
- TS_PATH=/opt/torrserver/config
|
||||||
|
- TS_LOGPATHDIR=/opt/torrserver/log
|
||||||
|
- TS_LOGFILE=ts.log
|
||||||
|
- TS_WEBLOGFILE=tsweb.log
|
||||||
|
- TS_RDB=false
|
||||||
|
- TS_HTTPAUTH=true
|
||||||
|
- TS_DONTKILL=true
|
||||||
|
- TS_TORRENTSDIR=/opt/torrserver/torrents
|
||||||
|
- TS_TORRENTADDR=:32000
|
||||||
|
- TS_PUBIPV4=publicIP
|
||||||
|
- TS_PUBIPV6=publicIP
|
||||||
|
- TS_SEARCHWA=true
|
||||||
|
ports:
|
||||||
|
- 8090:8090
|
||||||
|
volumes:
|
||||||
|
- ./torrserver/config:/opt/torrserver/config
|
||||||
|
- ./torrserver/log:/opt/torrserver/log
|
||||||
|
- ./torrserver/torrents:/opt/torrserver/torrents
|
||||||
|
```
|
||||||
49
docker/start.sh
Normal file
49
docker/start.sh
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
case $(uname -m) in
|
||||||
|
i386) architecture="386" ;;
|
||||||
|
i686) architecture="386" ;;
|
||||||
|
x86_64) architecture="amd64" ;;
|
||||||
|
aarch64) architecture="arm64" ;;
|
||||||
|
armv7|armv7l) architecture="arm7" ;;
|
||||||
|
armv6|armv6l) architecture="arm5" ;;
|
||||||
|
# armv5|armv5l) architecture="arm5" ;;
|
||||||
|
*) echo "Unsupported Arch. Can't continue."; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
binName="TorrServer-linux-${architecture}"
|
||||||
|
|
||||||
|
mkdir -p /opt/torrserver
|
||||||
|
cd /opt/torrserver
|
||||||
|
|
||||||
|
rm -f ${binName}*
|
||||||
|
|
||||||
|
wget -O $binName "https://github.com/YouROK/TorrServer/releases/latest/download/$binName"
|
||||||
|
chmod +x $binName
|
||||||
|
|
||||||
|
FLAGS=""
|
||||||
|
|
||||||
|
#sets start flags
|
||||||
|
[ ! -z "$TS_PORT" ] && echo "TS_PORT: $TS_PORT" && FLAGS="${FLAGS} --port ${TS_PORT}"
|
||||||
|
[ ! -z "$TS_PATH" ] && echo "TS_PATH: $TS_PATH" && FLAGS="${FLAGS} --path ${TS_PATH}"
|
||||||
|
[ ! -z "$TS_LOGPATHDIR" ] && echo "TS_LOGPATHDIR: $TS_LOGPATHDIR" && FLAGS="${FLAGS}"
|
||||||
|
[ ! -z "$TS_LOGFILE" ] && echo "TS_LOGFILE: $TS_LOGPATHDIR/$TS_LOGFILE" && FLAGS="${FLAGS} --logpath $TS_LOGPATHDIR/${TS_LOGFILE}"
|
||||||
|
[ ! -z "$TS_WEBLOGFILE" ] && echo "TS_WEBLOGFILE: $TS_LOGPATHDIR/$TS_WEBLOGFILE" && FLAGS="${FLAGS} --weblogpath $TS_LOGPATHDIR/${TS_WEBLOGFILE}"
|
||||||
|
[ ! -z "$TS_RDB" ] | [ "$TS_RDB" = "true" ] && echo "TS_RDB: $TS_RDB" && FLAGS="${FLAGS} --rdb"
|
||||||
|
[ ! -z "$TS_HTTPAUTH" ] && echo "TS_HTTPAUTH: $TS_HTTPAUTH" && FLAGS="${FLAGS} --httpauth"
|
||||||
|
[ ! -z "$TS_DONTKILL" ] && echo "TS_DONTKILL: $TS_DONTKILL" && FLAGS="${FLAGS} --dontkill"
|
||||||
|
[ ! -z "$TS_TORRENTSDIR" ] && echo "TS_TORRENTSDIR: $TS_TORRENTSDIR" && FLAGS="${FLAGS} --torrentsdir ${TS_TORRENTSDIR}"
|
||||||
|
[ ! -z "$TS_TORRENTADDR" ] && echo "TS_TORRENTADDR: $TS_TORRENTADDR" && FLAGS="${FLAGS} --torrentaddr ${TS_TORRENTADDR}"
|
||||||
|
[ ! -z "$TS_PUBIPV4" ] && echo "TS_PUBIPV4: $TS_PUBIPV4" && FLAGS="${FLAGS} --pubipv4 ${TS_PUBIPV4}"
|
||||||
|
[ ! -z "$TS_PUBIPV6" ] && echo "TS_PUBIPV6: $TS_PUBIPV6" && FLAGS="${FLAGS} --pubipv6 ${TS_PUBIPV6}"
|
||||||
|
[ ! -z "$TS_SEARCHWA" ]&& echo "TS_SEARCHWA: $TS_SEARCHWA" && FLAGS="${FLAGS} --searchwa"
|
||||||
|
|
||||||
|
#make directories
|
||||||
|
[ ! -z "$TS_PATH" ] && [ ! -d "$TS_PATH" ] && mkdir -p $TS_PATH
|
||||||
|
[ ! -z "$TS_LOGPATHDIR" ] && [ ! -d "$TS_LOGPATHDIR" ] && mkdir -p $TS_LOGPATHDIR
|
||||||
|
[ ! -z "$TS_TORRENTSDIR" ] && [ ! -d "$TS_TORRENTSDIR" ] && mkdir $TS_TORRENTSDIR
|
||||||
|
|
||||||
|
echo "Running with: ${FLAGS}"
|
||||||
|
export GODEBUG=madvdontneed=1
|
||||||
|
|
||||||
|
/opt/torrserver/${binName} ${FLAGS}
|
||||||
10
gen_web.go
10
gen_web.go
@@ -82,11 +82,16 @@ func writeRoute(fname string, fmap map[string]string) {
|
|||||||
embedStr := `package template
|
embedStr := `package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RouteWebPages(route *gin.RouterGroup) {
|
func RouteWebPages(route gin.IRouter) {
|
||||||
route.GET("/", func(c *gin.Context) {
|
route.GET("/", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Indexhtml))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "text/html; charset=utf-8", Indexhtml)
|
c.Data(200, "text/html; charset=utf-8", Indexhtml)
|
||||||
})
|
})
|
||||||
`
|
`
|
||||||
@@ -108,6 +113,9 @@ func RouteWebPages(route *gin.RouterGroup) {
|
|||||||
}
|
}
|
||||||
embedStr += `
|
embedStr += `
|
||||||
route.GET("` + link + `", func(c *gin.Context) {
|
route.GET("` + link + `", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(` + fmap[link] + `))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "` + fmime + `", ` + fmap[link] + `)
|
c.Data(200, "` + fmime + `", ` + fmap[link] + `)
|
||||||
})
|
})
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ function killRunning() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
sudo rm -f /Library/LaunchAgents/*torrserver* 1>/dev/null 2>&1
|
sudo rm -f /Library/LaunchAgents/*torrserver*
|
||||||
sudo rm -f /Library/LaunchDaemons/*torrserver* 1>/dev/null 2>&1
|
sudo rm -f /Library/LaunchDaemons/*torrserver*
|
||||||
sudo rm -f $HOME/Library/LaunchAgents/*torrserver* 1>/dev/null 2>&1
|
sudo rm -f $HOME/Library/LaunchAgents/*torrserver*
|
||||||
sudo rm -f $HOME/Library/LaunchDaemons/*torrserver* 1>/dev/null 2>&1
|
sudo rm -f $HOME/Library/LaunchDaemons/*torrserver*
|
||||||
killRunning
|
killRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,6 @@ function uninstall() {
|
|||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
[[ $lang == "en" ]] && read -p ' Are you shure you want to delete TorrServer? (Yes/No) ' answer_del </dev/tty || read -p ' Вы уверены что хотите удалить программу? (Да/Нет) ' answer_del </dev/tty
|
[[ $lang == "en" ]] && read -p ' Are you shure you want to delete TorrServer? (Yes/No) ' answer_del </dev/tty || read -p ' Вы уверены что хотите удалить программу? (Да/Нет) ' answer_del </dev/tty
|
||||||
read answer_del
|
|
||||||
if [ "$answer_del" != "${answer_del#[YyДд]}" ]; then
|
if [ "$answer_del" != "${answer_del#[YyДд]}" ]; then
|
||||||
cleanup
|
cleanup
|
||||||
sudo rm -rf $dirInstall
|
sudo rm -rf $dirInstall
|
||||||
@@ -80,6 +79,7 @@ function installTorrServer() {
|
|||||||
echo " Устанавливаем TorrServer $(getLatestRelease)…"
|
echo " Устанавливаем TorrServer $(getLatestRelease)…"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
user=$(whoami)
|
||||||
binName="TorrServer-darwin-${architecture}"
|
binName="TorrServer-darwin-${architecture}"
|
||||||
[[ ! -d "$dirInstall" ]] && mkdir -p ${dirInstall} && chmod a+rw ${dirInstall}
|
[[ ! -d "$dirInstall" ]] && mkdir -p ${dirInstall} && chmod a+rw ${dirInstall}
|
||||||
urlBin="https://github.com/YouROK/TorrServer/releases/download/$(getLatestRelease)/${binName}"
|
urlBin="https://github.com/YouROK/TorrServer/releases/download/$(getLatestRelease)/${binName}"
|
||||||
@@ -179,6 +179,7 @@ EOF
|
|||||||
sysPath="${HOME}/Library/LaunchAgents"
|
sysPath="${HOME}/Library/LaunchAgents"
|
||||||
[[ ! -d "$sysPath" ]] && mkdir -p ${sysPath}
|
[[ ! -d "$sysPath" ]] && mkdir -p ${sysPath}
|
||||||
cp "$dirInstall/$serviceName.plist" $sysPath
|
cp "$dirInstall/$serviceName.plist" $sysPath
|
||||||
|
sudo chown $user "$sysPath/$serviceName.plist"
|
||||||
chmod 0644 "$sysPath/$serviceName.plist"
|
chmod 0644 "$sysPath/$serviceName.plist"
|
||||||
launchctl load -w "$sysPath/$serviceName.plist" 1>/dev/null 2>&1
|
launchctl load -w "$sysPath/$serviceName.plist" 1>/dev/null 2>&1
|
||||||
else
|
else
|
||||||
@@ -211,7 +212,7 @@ EOF
|
|||||||
[[ $lang == "en" ]] && echo " Use user \"$isAuthUser\" with password \"$isAuthPass\" for web auth" || echo " Для авторизации введите пользователя $isAuthUser с паролем $isAuthPass"
|
[[ $lang == "en" ]] && echo " Use user \"$isAuthUser\" with password \"$isAuthPass\" for web auth" || echo " Для авторизации введите пользователя $isAuthUser с паролем $isAuthPass"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
sleep 60
|
sleep 30
|
||||||
}
|
}
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -25,12 +26,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
Port string `arg:"-p" help:"web server port, default 8090"`
|
Port string `arg:"-p" help:"web server port (default 8090)"`
|
||||||
Ssl bool `help:"enables https"`
|
Ssl bool `help:"enables https"`
|
||||||
SslPort string `help:"web server ssl port, If not set, will be set to default 8091 or taken from db(if stored previously). Accepted if --ssl enabled."`
|
SslPort string `help:"web server ssl port, If not set, will be set to default 8091 or taken from db(if stored previously). Accepted if --ssl enabled."`
|
||||||
SslCert string `help:"path to ssl cert file. If not set, will be taken from db(if stored previously) or default self-signed certificate/key will be generated. Accepted if --ssl enabled."`
|
SslCert string `help:"path to ssl cert file. If not set, will be taken from db(if stored previously) or default self-signed certificate/key will be generated. Accepted if --ssl enabled."`
|
||||||
SslKey string `help:"path to ssl key file. If not set, will be taken from db(if stored previously) or default self-signed certificate/key will be generated. Accepted if --ssl enabled."`
|
SslKey string `help:"path to ssl key file. If not set, will be taken from db(if stored previously) or default self-signed certificate/key will be generated. Accepted if --ssl enabled."`
|
||||||
Path string `arg:"-d" help:"database dir path"`
|
Path string `arg:"-d" help:"database and config dir path"`
|
||||||
LogPath string `arg:"-l" help:"server log file path"`
|
LogPath string `arg:"-l" help:"server log file path"`
|
||||||
WebLogPath string `arg:"-w" help:"web access log file path"`
|
WebLogPath string `arg:"-w" help:"web access log file path"`
|
||||||
RDB bool `arg:"-r" help:"start in read-only DB mode"`
|
RDB bool `arg:"-r" help:"start in read-only DB mode"`
|
||||||
@@ -38,10 +39,11 @@ type args struct {
|
|||||||
DontKill bool `arg:"-k" help:"don't kill server on signal"`
|
DontKill bool `arg:"-k" help:"don't kill server on signal"`
|
||||||
UI bool `arg:"-u" help:"open torrserver page in browser"`
|
UI bool `arg:"-u" help:"open torrserver page in browser"`
|
||||||
TorrentsDir string `arg:"-t" help:"autoload torrents from dir"`
|
TorrentsDir string `arg:"-t" help:"autoload torrents from dir"`
|
||||||
TorrentAddr string `help:"Torrent client address, default :32000"`
|
TorrentAddr string `help:"Torrent client address, like 127.0.0.1:1337 (default :PeersListenPort)"`
|
||||||
PubIPv4 string `arg:"-4" help:"set public IPv4 addr"`
|
PubIPv4 string `arg:"-4" help:"set public IPv4 addr"`
|
||||||
PubIPv6 string `arg:"-6" help:"set public IPv6 addr"`
|
PubIPv6 string `arg:"-6" help:"set public IPv6 addr"`
|
||||||
SearchWA bool `arg:"-s" help:"search without auth"`
|
SearchWA bool `arg:"-s" help:"search without auth"`
|
||||||
|
MaxSize string `arg:"-m" help:"max allowed stream size (in Bytes)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (args) Version() string {
|
func (args) Version() string {
|
||||||
@@ -104,6 +106,13 @@ func main() {
|
|||||||
go watchTDir(params.TorrentsDir)
|
go watchTDir(params.TorrentsDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.MaxSize != "" {
|
||||||
|
maxSize, err := strconv.ParseInt(params.MaxSize, 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
settings.MaxSize = maxSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
server.Start(params.Port, params.SslPort, params.SslCert, params.SslKey, params.Ssl, params.RDB, params.SearchWA)
|
server.Start(params.Port, params.SslPort, params.SslCert, params.SslKey, params.Ssl, params.RDB, params.SearchWA)
|
||||||
log.TLogln(server.WaitServer())
|
log.TLogln(server.WaitServer())
|
||||||
log.Close()
|
log.Close()
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func Start() {
|
|||||||
FriendlyName: getDefaultFriendlyName(),
|
FriendlyName: getDefaultFriendlyName(),
|
||||||
NoTranscode: true,
|
NoTranscode: true,
|
||||||
NoProbe: true,
|
NoProbe: true,
|
||||||
StallEventSubscribe: true,
|
StallEventSubscribe: false,
|
||||||
Icons: []dms.Icon{
|
Icons: []dms.Icon{
|
||||||
{
|
{
|
||||||
Width: 48,
|
Width: 48,
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const docTemplate = `{
|
|||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Test file size",
|
"description": "Test file size (in MB)",
|
||||||
"name": "size",
|
"name": "size",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
@@ -98,7 +98,7 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/ffp": {
|
"/ffp/{hash}/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Gather informations using ffprobe.",
|
"description": "Gather informations using ffprobe.",
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -113,14 +113,14 @@ const docTemplate = `{
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Torrent hash",
|
"description": "Torrent hash",
|
||||||
"name": "hash",
|
"name": "hash",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "File index in torrent",
|
"description": "File index in torrent",
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -148,32 +148,6 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/msx": {
|
|
||||||
"get": {
|
|
||||||
"description": "Multi usage endpoint.",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"MSX"
|
|
||||||
],
|
|
||||||
"summary": "Multi usage endpoint",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Magnet/hash/link to torrent",
|
|
||||||
"name": "link",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Data returned according to query"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/msx/imdb": {
|
"/msx/imdb": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get MSX IMDB informations.",
|
"description": "Get MSX IMDB informations.",
|
||||||
@@ -191,7 +165,7 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/msx/imdb/:id": {
|
"/msx/imdb/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get MSX IMDB informations.",
|
"description": "Get MSX IMDB informations.",
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -217,7 +191,33 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/play": {
|
"/msx/{pth}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Multi usage endpoint.",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MSX"
|
||||||
|
],
|
||||||
|
"summary": "Multi usage endpoint",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Route MSX pages",
|
||||||
|
"name": "link",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Data returned according to path"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/play/{hash}/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Play given torrent referenced by hash.",
|
"description": "Play given torrent referenced by hash.",
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -232,21 +232,15 @@ const docTemplate = `{
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Torrent hash",
|
"description": "Torrent hash",
|
||||||
"name": "hash",
|
"name": "hash",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "File index in torrent",
|
"description": "File index in torrent",
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Not authenticated",
|
|
||||||
"name": "not_auth",
|
|
||||||
"in": "query"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -458,7 +452,7 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Get m3u from last play",
|
"description": "Get M3U from last played file",
|
||||||
"name": "fromlast",
|
"name": "fromlast",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -475,17 +469,10 @@ const docTemplate = `{
|
|||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "File index in torrent",
|
|
||||||
"name": "poster",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Set poster link of torrent",
|
"description": "Set poster link of torrent",
|
||||||
"name": "not_auth",
|
"name": "poster",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Test file size",
|
"description": "Test file size (in MB)",
|
||||||
"name": "size",
|
"name": "size",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/ffp": {
|
"/ffp/{hash}/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Gather informations using ffprobe.",
|
"description": "Gather informations using ffprobe.",
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -106,14 +106,14 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Torrent hash",
|
"description": "Torrent hash",
|
||||||
"name": "hash",
|
"name": "hash",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "File index in torrent",
|
"description": "File index in torrent",
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -141,32 +141,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/msx": {
|
|
||||||
"get": {
|
|
||||||
"description": "Multi usage endpoint.",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"MSX"
|
|
||||||
],
|
|
||||||
"summary": "Multi usage endpoint",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "Magnet/hash/link to torrent",
|
|
||||||
"name": "link",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "Data returned according to query"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/msx/imdb": {
|
"/msx/imdb": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get MSX IMDB informations.",
|
"description": "Get MSX IMDB informations.",
|
||||||
@@ -184,7 +158,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/msx/imdb/:id": {
|
"/msx/imdb/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Get MSX IMDB informations.",
|
"description": "Get MSX IMDB informations.",
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -210,7 +184,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/play": {
|
"/msx/{pth}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Multi usage endpoint.",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"MSX"
|
||||||
|
],
|
||||||
|
"summary": "Multi usage endpoint",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Route MSX pages",
|
||||||
|
"name": "link",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Data returned according to path"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/play/{hash}/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Play given torrent referenced by hash.",
|
"description": "Play given torrent referenced by hash.",
|
||||||
"produces": [
|
"produces": [
|
||||||
@@ -225,21 +225,15 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Torrent hash",
|
"description": "Torrent hash",
|
||||||
"name": "hash",
|
"name": "hash",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "File index in torrent",
|
"description": "File index in torrent",
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "query",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Not authenticated",
|
|
||||||
"name": "not_auth",
|
|
||||||
"in": "query"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
@@ -451,7 +445,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Get m3u from last play",
|
"description": "Get M3U from last played file",
|
||||||
"name": "fromlast",
|
"name": "fromlast",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
@@ -468,17 +462,10 @@
|
|||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "File index in torrent",
|
|
||||||
"name": "poster",
|
|
||||||
"in": "query",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Set poster link of torrent",
|
"description": "Set poster link of torrent",
|
||||||
"name": "not_auth",
|
"name": "poster",
|
||||||
"in": "query",
|
"in": "query",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ paths:
|
|||||||
get:
|
get:
|
||||||
description: Download the test file of given size (for speed testing purpose).
|
description: Download the test file of given size (for speed testing purpose).
|
||||||
parameters:
|
parameters:
|
||||||
- description: Test file size
|
- description: Test file size (in MB)
|
||||||
in: path
|
in: path
|
||||||
name: size
|
name: size
|
||||||
required: true
|
required: true
|
||||||
@@ -360,17 +360,17 @@ paths:
|
|||||||
summary: Tests server status
|
summary: Tests server status
|
||||||
tags:
|
tags:
|
||||||
- API
|
- API
|
||||||
/ffp:
|
/ffp/{hash}/{id}:
|
||||||
get:
|
get:
|
||||||
description: Gather informations using ffprobe.
|
description: Gather informations using ffprobe.
|
||||||
parameters:
|
parameters:
|
||||||
- description: Torrent hash
|
- description: Torrent hash
|
||||||
in: query
|
in: path
|
||||||
name: hash
|
name: hash
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
- description: File index in torrent
|
- description: File index in torrent
|
||||||
in: query
|
in: path
|
||||||
name: id
|
name: id
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
@@ -393,12 +393,12 @@ paths:
|
|||||||
summary: Get HTML of magnet links
|
summary: Get HTML of magnet links
|
||||||
tags:
|
tags:
|
||||||
- Pages
|
- Pages
|
||||||
/msx:
|
/msx/{pth}:
|
||||||
get:
|
get:
|
||||||
description: Multi usage endpoint.
|
description: Multi usage endpoint.
|
||||||
parameters:
|
parameters:
|
||||||
- description: Magnet/hash/link to torrent
|
- description: Route MSX pages
|
||||||
in: query
|
in: path
|
||||||
name: link
|
name: link
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
@@ -406,7 +406,7 @@ paths:
|
|||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Data returned according to query
|
description: Data returned according to path
|
||||||
summary: Multi usage endpoint
|
summary: Multi usage endpoint
|
||||||
tags:
|
tags:
|
||||||
- MSX
|
- MSX
|
||||||
@@ -421,7 +421,7 @@ paths:
|
|||||||
summary: Get MSX IMDB informations
|
summary: Get MSX IMDB informations
|
||||||
tags:
|
tags:
|
||||||
- MSX
|
- MSX
|
||||||
/msx/imdb/:id:
|
/msx/imdb/{id}:
|
||||||
get:
|
get:
|
||||||
description: Get MSX IMDB informations.
|
description: Get MSX IMDB informations.
|
||||||
parameters:
|
parameters:
|
||||||
@@ -438,24 +438,20 @@ paths:
|
|||||||
summary: Get MSX IMDB informations
|
summary: Get MSX IMDB informations
|
||||||
tags:
|
tags:
|
||||||
- MSX
|
- MSX
|
||||||
/play:
|
/play/{hash}/{id}:
|
||||||
get:
|
get:
|
||||||
description: Play given torrent referenced by hash.
|
description: Play given torrent referenced by hash.
|
||||||
parameters:
|
parameters:
|
||||||
- description: Torrent hash
|
- description: Torrent hash
|
||||||
in: query
|
in: path
|
||||||
name: hash
|
name: hash
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
- description: File index in torrent
|
- description: File index in torrent
|
||||||
in: query
|
in: path
|
||||||
name: id
|
name: id
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
- description: Not authenticated
|
|
||||||
in: query
|
|
||||||
name: not_auth
|
|
||||||
type: boolean
|
|
||||||
produces:
|
produces:
|
||||||
- application/octet-stream
|
- application/octet-stream
|
||||||
responses:
|
responses:
|
||||||
@@ -592,7 +588,7 @@ paths:
|
|||||||
in: query
|
in: query
|
||||||
name: m3u
|
name: m3u
|
||||||
type: string
|
type: string
|
||||||
- description: Get m3u from last play
|
- description: Get M3U from last played file
|
||||||
in: query
|
in: query
|
||||||
name: fromlast
|
name: fromlast
|
||||||
type: string
|
type: string
|
||||||
@@ -605,14 +601,9 @@ paths:
|
|||||||
name: title
|
name: title
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
- description: File index in torrent
|
|
||||||
in: query
|
|
||||||
name: poster
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
- description: Set poster link of torrent
|
- description: Set poster link of torrent
|
||||||
in: query
|
in: query
|
||||||
name: not_auth
|
name: poster
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
produces:
|
produces:
|
||||||
|
|||||||
@@ -2,51 +2,52 @@ module server
|
|||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
replace github.com/anacrolix/torrent v1.53.1 => github.com/tsynik/torrent v1.2.11
|
replace github.com/anacrolix/torrent v1.54.1 => github.com/tsynik/torrent v1.2.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/agnivade/levenshtein v1.1.1
|
github.com/agnivade/levenshtein v1.1.1
|
||||||
github.com/alexflint/go-arg v1.4.3
|
github.com/alexflint/go-arg v1.4.3
|
||||||
github.com/anacrolix/dms v1.6.0
|
github.com/anacrolix/dms v1.6.0
|
||||||
github.com/anacrolix/log v0.14.5
|
github.com/anacrolix/log v0.15.0
|
||||||
github.com/anacrolix/missinggo v1.3.0
|
github.com/anacrolix/missinggo/v2 v2.7.3
|
||||||
github.com/anacrolix/publicip v0.3.0
|
github.com/anacrolix/publicip v0.3.0
|
||||||
github.com/anacrolix/torrent v1.53.1
|
github.com/anacrolix/torrent v1.54.1
|
||||||
github.com/gin-contrib/cors v1.4.0
|
github.com/gin-contrib/cors v1.5.0
|
||||||
github.com/gin-contrib/location v0.0.2
|
github.com/gin-contrib/location v0.0.2
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/kljensen/snowball v0.8.0
|
github.com/kljensen/snowball v0.9.0
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
github.com/swaggo/gin-swagger v1.6.0
|
github.com/swaggo/gin-swagger v1.6.0
|
||||||
github.com/swaggo/swag v1.16.2
|
github.com/swaggo/swag v1.16.3
|
||||||
go.etcd.io/bbolt v1.3.8
|
go.etcd.io/bbolt v1.3.9
|
||||||
golang.org/x/image v0.14.0
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
|
||||||
golang.org/x/time v0.4.0
|
golang.org/x/image v0.15.0
|
||||||
|
golang.org/x/time v0.5.0
|
||||||
gopkg.in/vansante/go-ffprobe.v2 v2.1.1
|
gopkg.in/vansante/go-ffprobe.v2 v2.1.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/RoaringBitmap/roaring v1.6.0 // indirect
|
github.com/RoaringBitmap/roaring v1.9.0 // indirect
|
||||||
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
||||||
github.com/alexflint/go-scalar v1.2.0 // indirect
|
github.com/alexflint/go-scalar v1.2.0 // indirect
|
||||||
github.com/anacrolix/chansync v0.3.0 // indirect
|
github.com/anacrolix/chansync v0.4.0 // indirect
|
||||||
github.com/anacrolix/dht/v2 v2.21.0 // indirect
|
github.com/anacrolix/dht/v2 v2.21.1 // indirect
|
||||||
github.com/anacrolix/ffprobe v1.1.0 // indirect
|
github.com/anacrolix/ffprobe v1.1.0 // indirect
|
||||||
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 // indirect
|
github.com/anacrolix/generics v0.0.1 // indirect
|
||||||
|
github.com/anacrolix/missinggo v1.3.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.7.3 // indirect
|
|
||||||
github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 // indirect
|
github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 // indirect
|
||||||
github.com/anacrolix/stm v0.5.0 // indirect
|
github.com/anacrolix/stm v0.5.0 // indirect
|
||||||
github.com/anacrolix/sync v0.5.1 // indirect
|
github.com/anacrolix/sync v0.5.1 // indirect
|
||||||
github.com/anacrolix/upnp v0.1.3 // indirect
|
github.com/anacrolix/upnp v0.1.4 // indirect
|
||||||
github.com/anacrolix/utp v0.2.0 // indirect
|
github.com/anacrolix/utp v0.2.0 // indirect
|
||||||
github.com/benbjohnson/immutable v0.4.3 // indirect
|
github.com/benbjohnson/immutable v0.4.3 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.11.0 // indirect
|
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||||
github.com/bytedance/sonic v1.10.2 // indirect
|
github.com/bytedance/sonic v1.11.1 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
@@ -55,38 +56,38 @@ require (
|
|||||||
github.com/frankban/quicktest v1.14.6 // indirect
|
github.com/frankban/quicktest v1.14.6 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.20.0 // indirect
|
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.4 // indirect
|
||||||
github.com/go-openapi/spec v0.20.9 // indirect
|
github.com/go-openapi/spec v0.20.14 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // indirect
|
github.com/go-openapi/swag v0.22.9 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.16.0 // indirect
|
github.com/go-playground/validator/v10 v10.18.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/huandu/xstrings v1.4.0 // indirect
|
github.com/huandu/xstrings v1.4.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
golang.org/x/arch v0.6.0 // indirect
|
golang.org/x/arch v0.7.0 // indirect
|
||||||
golang.org/x/crypto v0.15.0 // indirect
|
golang.org/x/crypto v0.19.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
|
golang.org/x/net v0.21.0 // indirect
|
||||||
golang.org/x/net v0.18.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/sync v0.5.0 // indirect
|
golang.org/x/sys v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.15.0 // indirect
|
golang.org/x/tools v0.18.0 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.32.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
179
server/go.sum
179
server/go.sum
@@ -8,8 +8,8 @@ github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6Xge
|
|||||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||||
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
||||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
github.com/RoaringBitmap/roaring v1.6.0 h1:dc7kRiroETgJcHhWX6BerXkZz2b3JgLGg9nTURJL/og=
|
github.com/RoaringBitmap/roaring v1.9.0 h1:lwKhr90/j0jVXJyh5X+vQN1VVn77rQFfYnh6RDRGCcE=
|
||||||
github.com/RoaringBitmap/roaring v1.6.0/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
|
github.com/RoaringBitmap/roaring v1.9.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
|
||||||
@@ -25,10 +25,10 @@ github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258m
|
|||||||
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
|
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
|
||||||
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
|
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
|
||||||
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
|
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
|
||||||
github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U=
|
github.com/anacrolix/chansync v0.4.0 h1:Md0HM7zYCAO4KwNwgcIRgxNsMxiRuk7D1Ha0Uo+2y60=
|
||||||
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
github.com/anacrolix/chansync v0.4.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
||||||
github.com/anacrolix/dht/v2 v2.21.0 h1:8nzI+faaynY9jOKmVgdmBZVrTo8B7ZE/LKEgN3Vl/Bs=
|
github.com/anacrolix/dht/v2 v2.21.1 h1:s1rKkfLLcmBHKv4v/mtMkIeHIEptzEFiB6xVu54+5/o=
|
||||||
github.com/anacrolix/dht/v2 v2.21.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g=
|
github.com/anacrolix/dht/v2 v2.21.1/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g=
|
||||||
github.com/anacrolix/dms v1.6.0 h1:v2g1Y+Fc/ICSEc+7M6B92oFcfcqa5LXYPhE4Hcm5tVA=
|
github.com/anacrolix/dms v1.6.0 h1:v2g1Y+Fc/ICSEc+7M6B92oFcfcqa5LXYPhE4Hcm5tVA=
|
||||||
github.com/anacrolix/dms v1.6.0/go.mod h1:5fAMpBcPFG4WQFh91zhf2E7/KYZ3/WmmRAf/WMoL0Q0=
|
github.com/anacrolix/dms v1.6.0/go.mod h1:5fAMpBcPFG4WQFh91zhf2E7/KYZ3/WmmRAf/WMoL0Q0=
|
||||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||||
@@ -38,14 +38,14 @@ github.com/anacrolix/ffprobe v1.0.0/go.mod h1:BIw+Bjol6CWjm/CRWrVLk2Vy+UYlkgmBZ0
|
|||||||
github.com/anacrolix/ffprobe v1.1.0 h1:eKBudnERW9zRJ0+ge6FzkQ0pWLyq142+FJrwRwSRMT4=
|
github.com/anacrolix/ffprobe v1.1.0 h1:eKBudnERW9zRJ0+ge6FzkQ0pWLyq142+FJrwRwSRMT4=
|
||||||
github.com/anacrolix/ffprobe v1.1.0/go.mod h1:MXe+zG/RRa5OdIf5+VYYfS/CfsSqOH7RrvGIqJBzqhI=
|
github.com/anacrolix/ffprobe v1.1.0/go.mod h1:MXe+zG/RRa5OdIf5+VYYfS/CfsSqOH7RrvGIqJBzqhI=
|
||||||
github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
||||||
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 h1:qwOprPTDMM3BASJRf84mmZnTXRsPGGJ8xoHKQS7m3so=
|
github.com/anacrolix/generics v0.0.1 h1:4WVhK6iLb3UAAAQP6I3uYlMOHcp9FqJC9j4n81Wv9Ks=
|
||||||
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
github.com/anacrolix/generics v0.0.1/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
||||||
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||||
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||||
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
|
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
|
||||||
github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
||||||
github.com/anacrolix/log v0.14.5 h1:OkMjBquVSRb742LkecSGDGaGpNoSrw4syRIm0eRdmrg=
|
github.com/anacrolix/log v0.15.0 h1:QIhbW5NDUL6P1Aml+ZfdaXJ+QFAnrO0K1EpFYs/nh9M=
|
||||||
github.com/anacrolix/log v0.14.5/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
github.com/anacrolix/log v0.15.0/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA=
|
||||||
github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
||||||
github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo=
|
||||||
github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y=
|
github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y=
|
||||||
@@ -70,8 +70,8 @@ github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DC
|
|||||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||||
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||||
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
||||||
github.com/anacrolix/upnp v0.1.3 h1:NlYEhE75adz2npEJKjbqyqnyW9qU4STookvSNXBJ5ao=
|
github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
|
||||||
github.com/anacrolix/upnp v0.1.3/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
|
github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
|
||||||
github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
|
github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
|
||||||
github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8=
|
github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
@@ -82,17 +82,17 @@ github.com/benbjohnson/immutable v0.4.3/go.mod h1:qJIKKSmdqz1tVzNtst1DZzvaqOU1on
|
|||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bits-and-blooms/bitset v1.11.0 h1:RMyy2mBBShArUAhfVRZJ2xyBO58KCBCtZFShw3umo6k=
|
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||||
github.com/bits-and-blooms/bitset v1.11.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
github.com/bytedance/sonic v1.11.1 h1:JC0+6c9FoWYYxakaoa+c5QTtJeiSZNeByOBhXtAFSn4=
|
||||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
github.com/bytedance/sonic v1.11.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
@@ -122,14 +122,14 @@ github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk=
|
||||||
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
|
github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI=
|
||||||
|
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||||
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
|
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
|
||||||
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
|
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
@@ -142,36 +142,25 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU=
|
||||||
github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
|
github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4=
|
||||||
github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
|
github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/Do=
|
||||||
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
|
github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
|
||||||
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
|
github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
|
||||||
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
|
||||||
github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8=
|
|
||||||
github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
|
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
|
||||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
|
||||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U=
|
||||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
@@ -189,7 +178,6 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
|
|||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@@ -200,8 +188,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
|||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
@@ -227,31 +216,25 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/kljensen/snowball v0.8.0 h1:WU4cExxK6sNW33AiGdbn4e8RvloHrhkAssu2mVJ11kg=
|
github.com/kljensen/snowball v0.9.0 h1:OpXkQBcic6vcPG+dChOGLIA/GNuVg47tbbIJ2s7Keas=
|
||||||
github.com/kljensen/snowball v0.8.0/go.mod h1:OGo5gFWjaeXqCu4iIrMl5OYip9XUJHGOU5eSkPjVg2A=
|
github.com/kljensen/snowball v0.9.0/go.mod h1:OGo5gFWjaeXqCu4iIrMl5OYip9XUJHGOU5eSkPjVg2A=
|
||||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
@@ -267,18 +250,16 @@ github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
|||||||
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -305,6 +286,7 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
|||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
|
||||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
||||||
@@ -323,57 +305,53 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||||
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
|
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
|
||||||
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
|
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
|
||||||
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
|
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||||
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
|
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tsynik/torrent v1.2.11 h1:wPJfxhO/ri10T1Xfi4X8DftwOF3A8geZ4cRQWKxnC2s=
|
github.com/tsynik/torrent v1.2.16 h1:jEXIkdPKIOerO+8b/12wTvEoLnjGFcHX7dMitTmrWH0=
|
||||||
github.com/tsynik/torrent v1.2.11/go.mod h1:AjuETm1Xae+Vk31UrvrSrb29bBunwMKGZLXK6T+AgPo=
|
github.com/tsynik/torrent v1.2.16/go.mod h1:c/K0Twt8E0qXJj02tl5FmjhGXSl0XzbFYrzkXTGqU+w=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
|
||||||
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||||
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
|
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||||
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||||
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
|
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
|
||||||
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@@ -381,6 +359,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
|||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -397,8 +376,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220524220425-1d687d428aca/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -409,8 +388,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -427,17 +406,15 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@@ -449,8 +426,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -460,8 +437,8 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
|
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||||
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
|
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -480,16 +457,13 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ
|
|||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
|
||||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
@@ -500,10 +474,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func Start(port, sslport, sslCert, sslKey string, sslEnabled, roSets, searchWA b
|
|||||||
l.Close()
|
l.Close()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.TLogln("Port", sslport, "already in use! Please set different port for HTTPS. Abort")
|
log.TLogln("Port", sslport, "already in use! Please set different ssl port for HTTPS. Abort")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ func Start(port, sslport, sslCert, sslKey string, sslEnabled, roSets, searchWA b
|
|||||||
l.Close()
|
l.Close()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.TLogln("Port", port, "already in use! Please set different sslport for HTTP. Abort")
|
log.TLogln("Port", port, "already in use! Please set different port for HTTP. Abort")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
// remove old disk caches
|
// remove old disk caches
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ type TDB struct {
|
|||||||
db *bolt.DB
|
db *bolt.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTDB() *TDB {
|
func NewTDB() TorrServerDB {
|
||||||
db, err := bolt.Open(filepath.Join(Path, "config.db"), 0o666, &bolt.Options{Timeout: 5 * time.Second})
|
db, err := bolt.Open(filepath.Join(Path, "config.db"), 0o666, &bolt.Options{Timeout: 5 * time.Second})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.TLogln(err)
|
log.TLogln(err)
|
||||||
@@ -68,10 +68,6 @@ func (v *TDB) Get(xpath, name string) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *TDB) Set(xpath, name string, value []byte) {
|
func (v *TDB) Set(xpath, name string, value []byte) {
|
||||||
if ReadOnly {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
spath := strings.Split(xpath, "/")
|
spath := strings.Split(xpath, "/")
|
||||||
if len(spath) == 0 {
|
if len(spath) == 0 {
|
||||||
return
|
return
|
||||||
@@ -139,10 +135,6 @@ func (v *TDB) List(xpath string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *TDB) Rem(xpath, name string) {
|
func (v *TDB) Rem(xpath, name string) {
|
||||||
if ReadOnly {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
spath := strings.Split(xpath, "/")
|
spath := strings.Split(xpath, "/")
|
||||||
if len(spath) == 0 {
|
if len(spath) == 0 {
|
||||||
return
|
return
|
||||||
|
|||||||
70
server/settings/dbreadcache.go
Normal file
70
server/settings/dbreadcache.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import "server/log"
|
||||||
|
|
||||||
|
type DBReadCache struct {
|
||||||
|
db TorrServerDB
|
||||||
|
listCache map[string][]string
|
||||||
|
dataCache map[[2]string][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDBReadCache(db TorrServerDB) TorrServerDB {
|
||||||
|
cdb := &DBReadCache{
|
||||||
|
db: db,
|
||||||
|
listCache: map[string][]string{},
|
||||||
|
dataCache: map[[2]string][]byte{},
|
||||||
|
}
|
||||||
|
return cdb
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DBReadCache) CloseDB() {
|
||||||
|
v.db.CloseDB()
|
||||||
|
v.db = nil
|
||||||
|
v.listCache = nil
|
||||||
|
v.dataCache = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DBReadCache) Get(xPath, name string) []byte {
|
||||||
|
cacheKey := v.makeDataCacheKey(xPath, name)
|
||||||
|
if data, ok := v.dataCache[cacheKey]; ok {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
data := v.db.Get(xPath, name)
|
||||||
|
v.dataCache[cacheKey] = data
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DBReadCache) Set(xPath, name string, value []byte) {
|
||||||
|
if ReadOnly {
|
||||||
|
log.TLogln("DB.Set: Read-only DB mode!", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cacheKey := v.makeDataCacheKey(xPath, name)
|
||||||
|
v.dataCache[cacheKey] = value
|
||||||
|
delete(v.listCache, xPath)
|
||||||
|
v.db.Set(xPath, name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DBReadCache) List(xPath string) []string {
|
||||||
|
if names, ok := v.listCache[xPath]; ok {
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
names := v.db.List(xPath)
|
||||||
|
v.listCache[xPath] = names
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DBReadCache) Rem(xPath, name string) {
|
||||||
|
if ReadOnly {
|
||||||
|
log.TLogln("DB.Rem: Read-only DB mode!", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cacheKey := v.makeDataCacheKey(xPath, name)
|
||||||
|
delete(v.dataCache, cacheKey)
|
||||||
|
delete(v.listCache, xPath)
|
||||||
|
v.db.Rem(xPath, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *DBReadCache) makeDataCacheKey(xPath, name string) [2]string {
|
||||||
|
return [2]string{xPath, name}
|
||||||
|
}
|
||||||
159
server/settings/jsondb.go
Normal file
159
server/settings/jsondb.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"server/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JsonDB struct {
|
||||||
|
Path string
|
||||||
|
filenameDelimiter string
|
||||||
|
filenameExtension string
|
||||||
|
fileMode fs.FileMode
|
||||||
|
xPathDelimeter string
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonDbLocks = make(map[string]*sync.Mutex)
|
||||||
|
|
||||||
|
func NewJsonDB() TorrServerDB {
|
||||||
|
settingsDB := &JsonDB{
|
||||||
|
Path: Path,
|
||||||
|
filenameDelimiter: ".",
|
||||||
|
filenameExtension: ".json",
|
||||||
|
fileMode: fs.FileMode(0o666),
|
||||||
|
xPathDelimeter: "/",
|
||||||
|
}
|
||||||
|
return settingsDB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) CloseDB() {
|
||||||
|
// Not necessary
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) Set(xPath, name string, value []byte) {
|
||||||
|
var err error = nil
|
||||||
|
jsonObj := map[string]interface{}{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(value, &jsonObj); err == nil {
|
||||||
|
if filename, err := v.xPathToFilename(xPath); err == nil {
|
||||||
|
v.lock(filename)
|
||||||
|
defer v.unlock(filename)
|
||||||
|
if root, err := v.readJsonFileAsMap(filename); err == nil {
|
||||||
|
root[name] = jsonObj
|
||||||
|
if err = v.writeMapAsJsonFile(filename, root); err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.log(fmt.Sprintf("Set: error writing entry %s->%s", xPath, name), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) Get(xPath, name string) []byte {
|
||||||
|
var err error = nil
|
||||||
|
if filename, err := v.xPathToFilename(xPath); err == nil {
|
||||||
|
v.lock(filename)
|
||||||
|
defer v.unlock(filename)
|
||||||
|
if root, err := v.readJsonFileAsMap(filename); err == nil {
|
||||||
|
if jsonData, ok := root[name]; ok {
|
||||||
|
if byteData, err := json.Marshal(jsonData); err == nil {
|
||||||
|
return byteData
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We assume this is not 'error' but 'no entry' which is normal
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.log(fmt.Sprintf("Get: error reading entry %s->%s", xPath, name), err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) List(xPath string) []string {
|
||||||
|
var err error = nil
|
||||||
|
if filename, err := v.xPathToFilename(xPath); err == nil {
|
||||||
|
v.lock(filename)
|
||||||
|
defer v.unlock(filename)
|
||||||
|
if root, err := v.readJsonFileAsMap(filename); err == nil {
|
||||||
|
nameList := make([]string, 0, len(root))
|
||||||
|
for k := range root {
|
||||||
|
nameList = append(nameList, k)
|
||||||
|
}
|
||||||
|
return nameList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.log(fmt.Sprintf("List: error reading entries in xPath %s", xPath), err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) Rem(xPath, name string) {
|
||||||
|
var err error = nil
|
||||||
|
if filename, err := v.xPathToFilename(xPath); err == nil {
|
||||||
|
v.lock(filename)
|
||||||
|
defer v.unlock(filename)
|
||||||
|
if root, err := v.readJsonFileAsMap(filename); err == nil {
|
||||||
|
delete(root, name)
|
||||||
|
v.writeMapAsJsonFile(filename, root)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.log(fmt.Sprintf("Rem: error removing entry %s->%s", xPath, name), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) lock(filename string) {
|
||||||
|
var mtx sync.Mutex
|
||||||
|
if mtx, ok := jsonDbLocks[filename]; !ok {
|
||||||
|
mtx = new(sync.Mutex)
|
||||||
|
jsonDbLocks[v.Path] = mtx
|
||||||
|
}
|
||||||
|
mtx.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) unlock(filename string) {
|
||||||
|
if mtx, ok := jsonDbLocks[filename]; ok {
|
||||||
|
mtx.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) xPathToFilename(xPath string) (string, error) {
|
||||||
|
if pathComponents := strings.Split(xPath, v.xPathDelimeter); len(pathComponents) > 0 {
|
||||||
|
return strings.ToLower(strings.Join(pathComponents, v.filenameDelimiter) + v.filenameExtension), nil
|
||||||
|
}
|
||||||
|
return "", errors.New("xPath has no components")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) readJsonFileAsMap(filename string) (map[string]interface{}, error) {
|
||||||
|
var err error = nil
|
||||||
|
jsonData := map[string]interface{}{}
|
||||||
|
path := filepath.Join(v.Path, filename)
|
||||||
|
if fileData, err := os.ReadFile(path); err == nil {
|
||||||
|
err = json.Unmarshal(fileData, &jsonData)
|
||||||
|
}
|
||||||
|
return jsonData, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) writeMapAsJsonFile(filename string, o map[string]interface{}) error {
|
||||||
|
var err error = nil
|
||||||
|
path := filepath.Join(v.Path, filename)
|
||||||
|
|
||||||
|
if fileData, err := json.MarshalIndent(o, "", " "); err == nil {
|
||||||
|
err = os.WriteFile(path, fileData, v.fileMode)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *JsonDB) log(s string, params ...interface{}) {
|
||||||
|
if len(params) > 0 {
|
||||||
|
log.TLogln(fmt.Sprintf("JsonDB: %s: %s", s, fmt.Sprint(params...)))
|
||||||
|
} else {
|
||||||
|
log.TLogln(fmt.Sprintf("JsonDB: %s", s))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,13 +2,17 @@ package settings
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
bolt "go.etcd.io/bbolt"
|
|
||||||
"server/log"
|
"server/log"
|
||||||
"server/web/api/utils"
|
"server/web/api/utils"
|
||||||
|
|
||||||
|
bolt "go.etcd.io/bbolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var dbTorrentsName = []byte("Torrents")
|
var dbTorrentsName = []byte("Torrents")
|
||||||
@@ -22,7 +26,8 @@ type torrentOldDB struct {
|
|||||||
Timestamp int64
|
Timestamp int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func Migrate() {
|
// Migrate from torrserver.db to config.db
|
||||||
|
func Migrate1() {
|
||||||
if _, err := os.Lstat(filepath.Join(Path, "torrserver.db")); os.IsNotExist(err) {
|
if _, err := os.Lstat(filepath.Join(Path, "torrserver.db")); os.IsNotExist(err) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -100,3 +105,87 @@ func Migrate() {
|
|||||||
func b2i(v []byte) int64 {
|
func b2i(v []byte) int64 {
|
||||||
return int64(binary.BigEndian.Uint64(v))
|
return int64(binary.BigEndian.Uint64(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=== Migrate 2 ===
|
||||||
|
|
||||||
|
Migrate 'Settings' and 'Viewed' buckets from BBolt ('config.db')
|
||||||
|
to separate JSON files ('settings.json' and 'viewed.json')
|
||||||
|
|
||||||
|
'Torrents' data continues to remain in the BBolt database ('config.db')
|
||||||
|
due to the fact that BLOBs are stored there
|
||||||
|
|
||||||
|
To make user be able to roll settings back, no data is deleted from 'config.db' file.
|
||||||
|
*/
|
||||||
|
func Migrate2(bboltDB, jsonDB TorrServerDB) error {
|
||||||
|
var err error = nil
|
||||||
|
|
||||||
|
const XPATH_SETTINGS = "Settings"
|
||||||
|
const NAME_BITTORR = "BitTorr"
|
||||||
|
const XPATH_VIEWED = "Viewed"
|
||||||
|
|
||||||
|
if BTsets != nil {
|
||||||
|
msg := "Migrate0002 MUST be called before initializing BTSets"
|
||||||
|
log.TLogln(msg)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
isByteArraysEqualJson := func(a, b []byte) (bool, error) {
|
||||||
|
var objectA interface{}
|
||||||
|
var objectB interface{}
|
||||||
|
var err error = nil
|
||||||
|
if err = json.Unmarshal(a, &objectA); err == nil {
|
||||||
|
if err = json.Unmarshal(b, &objectB); err == nil {
|
||||||
|
return reflect.DeepEqual(objectA, objectB), nil
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("Error unmashalling B: %s", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("Error unmashalling A: %s", err.Error())
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
migrateXPath := func(xPath, name string) error {
|
||||||
|
if jsonDB.Get(xPath, name) == nil {
|
||||||
|
bboltDBBlob := bboltDB.Get(xPath, name)
|
||||||
|
if bboltDBBlob != nil {
|
||||||
|
log.TLogln(fmt.Sprintf("Attempting to migrate %s->%s from TDB to JsonDB", xPath, name))
|
||||||
|
jsonDB.Set(xPath, name, bboltDBBlob)
|
||||||
|
jsonDBBlob := jsonDB.Get(xPath, name)
|
||||||
|
if isEqual, err := isByteArraysEqualJson(bboltDBBlob, jsonDBBlob); err == nil {
|
||||||
|
if isEqual {
|
||||||
|
log.TLogln(fmt.Sprintf("Migrated %s->%s successful", xPath, name))
|
||||||
|
} else {
|
||||||
|
msg := fmt.Sprintf("Failed to migrate %s->%s TDB to JsonDB: equality check failed", xPath, name)
|
||||||
|
log.TLogln(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg := fmt.Sprintf("Failed to migrate %s->%s TDB to JsonDB: %s", xPath, name, err)
|
||||||
|
log.TLogln(msg)
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = migrateXPath(XPATH_SETTINGS, NAME_BITTORR); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonDBViewedNames := jsonDB.List(XPATH_VIEWED)
|
||||||
|
if len(jsonDBViewedNames) <= 0 {
|
||||||
|
bboltDBViewedNames := bboltDB.List(XPATH_VIEWED)
|
||||||
|
if len(bboltDBViewedNames) > 0 {
|
||||||
|
for _, name := range bboltDBViewedNames {
|
||||||
|
err = migrateXPath(XPATH_VIEWED, name)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tdb *TDB
|
tdb TorrServerDB
|
||||||
Path string
|
Path string
|
||||||
Port string
|
Port string
|
||||||
Ssl bool
|
Ssl bool
|
||||||
@@ -19,18 +20,40 @@ var (
|
|||||||
PubIPv4 string
|
PubIPv4 string
|
||||||
PubIPv6 string
|
PubIPv6 string
|
||||||
TorAddr string
|
TorAddr string
|
||||||
|
MaxSize int64
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitSets(readOnly, searchWA bool) {
|
func InitSets(readOnly, searchWA bool) {
|
||||||
ReadOnly = readOnly
|
ReadOnly = readOnly
|
||||||
SearchWA = searchWA
|
SearchWA = searchWA
|
||||||
tdb = NewTDB()
|
|
||||||
if tdb == nil {
|
bboltDB := NewTDB()
|
||||||
log.TLogln("Error open db:", filepath.Join(Path, "config.db"))
|
if bboltDB == nil {
|
||||||
|
log.TLogln("Error open bboltDB:", filepath.Join(Path, "config.db"))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonDB := NewJsonDB()
|
||||||
|
if jsonDB == nil {
|
||||||
|
log.TLogln("Error open jsonDB")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbRouter := NewXPathDBRouter()
|
||||||
|
// First registered DB becomes default route
|
||||||
|
dbRouter.RegisterRoute(jsonDB, "Settings")
|
||||||
|
dbRouter.RegisterRoute(jsonDB, "Viewed")
|
||||||
|
dbRouter.RegisterRoute(bboltDB, "Torrents")
|
||||||
|
|
||||||
|
tdb = NewDBReadCache(dbRouter)
|
||||||
|
|
||||||
|
// We migrate settings here, it must be done before loadBTSets()
|
||||||
|
if err := Migrate2(bboltDB, jsonDB); err != nil {
|
||||||
|
log.TLogln(fmt.Sprintf("Migrate2 failed"))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
loadBTSets()
|
loadBTSets()
|
||||||
Migrate()
|
Migrate1()
|
||||||
}
|
}
|
||||||
|
|
||||||
func CloseDB() {
|
func CloseDB() {
|
||||||
|
|||||||
9
server/settings/torrserverdb.go
Normal file
9
server/settings/torrserverdb.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
type TorrServerDB interface {
|
||||||
|
CloseDB()
|
||||||
|
Get(xPath, name string) []byte
|
||||||
|
Set(xPath, name string, value []byte)
|
||||||
|
List(xPath string) []string
|
||||||
|
Rem(xPath, name string)
|
||||||
|
}
|
||||||
119
server/settings/xpathdbrouter.go
Normal file
119
server/settings/xpathdbrouter.go
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"server/log"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
type XPathDBRouter struct {
|
||||||
|
dbs []TorrServerDB
|
||||||
|
routes []string
|
||||||
|
route2db map[string]TorrServerDB
|
||||||
|
dbNames map[TorrServerDB]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewXPathDBRouter() *XPathDBRouter {
|
||||||
|
router := &XPathDBRouter{
|
||||||
|
dbs: []TorrServerDB{},
|
||||||
|
dbNames: map[TorrServerDB]string{},
|
||||||
|
routes: []string{},
|
||||||
|
route2db: map[string]TorrServerDB{},
|
||||||
|
}
|
||||||
|
return router
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) RegisterRoute(db TorrServerDB, xPath string) error {
|
||||||
|
newRoute := v.xPathToRoute(xPath)
|
||||||
|
|
||||||
|
if slices.Contains(v.routes, newRoute) {
|
||||||
|
return errors.New(fmt.Sprintf("route \"%s\" already in routing table", newRoute))
|
||||||
|
}
|
||||||
|
|
||||||
|
// First DB becomes Default DB with default route
|
||||||
|
if len(v.dbs) == 0 && len(newRoute) != 0 {
|
||||||
|
v.RegisterRoute(db, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !slices.Contains(v.dbs, db) {
|
||||||
|
v.dbs = append(v.dbs, db)
|
||||||
|
v.dbNames[db] = reflect.TypeOf(db).Elem().Name()
|
||||||
|
v.log(fmt.Sprintf("Registered new DB \"%s\", total %d DBs registered", v.getDBName(db), len(v.dbs)))
|
||||||
|
}
|
||||||
|
|
||||||
|
v.route2db[newRoute] = db
|
||||||
|
v.routes = append(v.routes, newRoute)
|
||||||
|
|
||||||
|
// Sort routes by length descending.
|
||||||
|
// It is important later to help selecting
|
||||||
|
// most suitable route in getDBForXPath(xPath)
|
||||||
|
sort.Slice(v.routes, func(iLeft, iRight int) bool {
|
||||||
|
return len(v.routes[iLeft]) > len(v.routes[iRight])
|
||||||
|
})
|
||||||
|
v.log(fmt.Sprintf("Registered new route \"%s\" for DB \"%s\", total %d routes", newRoute, v.getDBName(db), len(v.routes)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) xPathToRoute(xPath string) string {
|
||||||
|
return strings.ToLower(strings.TrimSpace(xPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) getDBForXPath(xPath string) TorrServerDB {
|
||||||
|
if len(v.dbs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
lookup_route := v.xPathToRoute(xPath)
|
||||||
|
var db TorrServerDB = nil
|
||||||
|
// Expected v.routes sorted by length descending
|
||||||
|
for _, route_prefix := range v.routes {
|
||||||
|
if strings.HasPrefix(lookup_route, route_prefix) {
|
||||||
|
db = v.route2db[route_prefix]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) Get(xPath, name string) []byte {
|
||||||
|
return v.getDBForXPath(xPath).Get(xPath, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) Set(xPath, name string, value []byte) {
|
||||||
|
v.getDBForXPath(xPath).Set(xPath, name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) List(xPath string) []string {
|
||||||
|
return v.getDBForXPath(xPath).List(xPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) Rem(xPath, name string) {
|
||||||
|
v.getDBForXPath(xPath).Rem(xPath, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) CloseDB() {
|
||||||
|
for _, db := range v.dbs {
|
||||||
|
db.CloseDB()
|
||||||
|
}
|
||||||
|
v.dbs = nil
|
||||||
|
v.routes = nil
|
||||||
|
v.route2db = nil
|
||||||
|
v.dbNames = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) getDBName(db TorrServerDB) string {
|
||||||
|
return v.dbNames[db]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *XPathDBRouter) log(s string, params ...interface{}) {
|
||||||
|
if len(params) > 0 {
|
||||||
|
log.TLogln(fmt.Sprintf("XPathDBRouter: %s: %s", s, fmt.Sprint(params...)))
|
||||||
|
} else {
|
||||||
|
log.TLogln(fmt.Sprintf("XPathDBRouter: %s", s))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -150,19 +150,24 @@ func SetTorrent(hashHex, title, poster, data string) *Torrent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RemTorrent(hashHex string) {
|
func RemTorrent(hashHex string) {
|
||||||
|
if sets.ReadOnly {
|
||||||
|
log.TLogln("API RemTorrent: Read-only DB mode!", hashHex)
|
||||||
|
return
|
||||||
|
}
|
||||||
hash := metainfo.NewHashFromHex(hashHex)
|
hash := metainfo.NewHashFromHex(hashHex)
|
||||||
if sets.BTsets.UseDisk && hashHex != "" && hashHex != "/" {
|
if bts.RemoveTorrent(hash) {
|
||||||
name := filepath.Join(sets.BTsets.TorrentsSavePath, hashHex)
|
if sets.BTsets.UseDisk && hashHex != "" && hashHex != "/" {
|
||||||
ff, _ := os.ReadDir(name)
|
name := filepath.Join(sets.BTsets.TorrentsSavePath, hashHex)
|
||||||
for _, f := range ff {
|
ff, _ := os.ReadDir(name)
|
||||||
os.Remove(filepath.Join(name, f.Name()))
|
for _, f := range ff {
|
||||||
}
|
os.Remove(filepath.Join(name, f.Name()))
|
||||||
err := os.Remove(name)
|
}
|
||||||
if err != nil {
|
err := os.Remove(name)
|
||||||
log.TLogln("Error remove cache:", err)
|
if err != nil {
|
||||||
|
log.TLogln("Error remove cache:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bts.RemoveTorrent(hash)
|
|
||||||
RemTorrentDB(hash)
|
RemTorrentDB(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +204,7 @@ func DropTorrent(hashHex string) {
|
|||||||
|
|
||||||
func SetSettings(set *sets.BTSets) {
|
func SetSettings(set *sets.BTSets) {
|
||||||
if sets.ReadOnly {
|
if sets.ReadOnly {
|
||||||
|
log.TLogln("API SetSettings: Read-only DB mode!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sets.SetBTSets(set)
|
sets.SetBTSets(set)
|
||||||
@@ -215,6 +221,7 @@ func SetSettings(set *sets.BTSets) {
|
|||||||
|
|
||||||
func SetDefSettings() {
|
func SetDefSettings() {
|
||||||
if sets.ReadOnly {
|
if sets.ReadOnly {
|
||||||
|
log.TLogln("API SetDefSettings: Read-only DB mode!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sets.SetDefaultConfig()
|
sets.SetDefaultConfig()
|
||||||
|
|||||||
@@ -88,14 +88,13 @@ func (bt *BTServer) configure(ctx context.Context) {
|
|||||||
upnpID := "TorrServer/" + version.Version
|
upnpID := "TorrServer/" + version.Version
|
||||||
cliVers := userAgent
|
cliVers := userAgent
|
||||||
|
|
||||||
// bt.config.AlwaysWantConns = true
|
|
||||||
bt.config.Debug = settings.BTsets.EnableDebug
|
bt.config.Debug = settings.BTsets.EnableDebug
|
||||||
bt.config.DisableIPv6 = !settings.BTsets.EnableIPv6
|
bt.config.DisableIPv6 = !settings.BTsets.EnableIPv6
|
||||||
bt.config.DisableTCP = settings.BTsets.DisableTCP
|
bt.config.DisableTCP = settings.BTsets.DisableTCP
|
||||||
bt.config.DisableUTP = settings.BTsets.DisableUTP
|
bt.config.DisableUTP = settings.BTsets.DisableUTP
|
||||||
// https://github.com/anacrolix/torrent/issues/703
|
// https://github.com/anacrolix/torrent/issues/703
|
||||||
// bt.config.DisableWebtorrent = true // TODO: check memory usage
|
// bt.config.DisableWebtorrent = true // NE
|
||||||
// bt.config.DisableWebseeds = false
|
// bt.config.DisableWebseeds = false // NE
|
||||||
bt.config.NoDefaultPortForwarding = settings.BTsets.DisableUPNP
|
bt.config.NoDefaultPortForwarding = settings.BTsets.DisableUPNP
|
||||||
bt.config.NoDHT = settings.BTsets.DisableDHT
|
bt.config.NoDHT = settings.BTsets.DisableDHT
|
||||||
bt.config.DisablePEX = settings.BTsets.DisablePEX
|
bt.config.DisablePEX = settings.BTsets.DisablePEX
|
||||||
@@ -109,13 +108,13 @@ func (bt *BTServer) configure(ctx context.Context) {
|
|||||||
bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit
|
bt.config.EstablishedConnsPerTorrent = settings.BTsets.ConnectionsLimit
|
||||||
bt.config.TotalHalfOpenConns = 500
|
bt.config.TotalHalfOpenConns = 500
|
||||||
// Encryption/Obfuscation
|
// Encryption/Obfuscation
|
||||||
bt.config.EncryptionPolicy = torrent.EncryptionPolicy{
|
bt.config.EncryptionPolicy = torrent.EncryptionPolicy{ // OE
|
||||||
ForceEncryption: settings.BTsets.ForceEncrypt,
|
ForceEncryption: settings.BTsets.ForceEncrypt, // OE
|
||||||
}
|
} // OE
|
||||||
// bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{
|
// bt.config.HeaderObfuscationPolicy = torrent.HeaderObfuscationPolicy{ // NE
|
||||||
// RequirePreferred: settings.BTsets.ForceEncrypt,
|
// RequirePreferred: settings.BTsets.ForceEncrypt, // NE
|
||||||
// Preferred: true,
|
// Preferred: true, // NE
|
||||||
// }
|
// } // NE
|
||||||
if settings.BTsets.DownloadRateLimit > 0 {
|
if settings.BTsets.DownloadRateLimit > 0 {
|
||||||
bt.config.DownloadRateLimiter = utils.Limit(settings.BTsets.DownloadRateLimit * 1024)
|
bt.config.DownloadRateLimiter = utils.Limit(settings.BTsets.DownloadRateLimit * 1024)
|
||||||
}
|
}
|
||||||
@@ -130,21 +129,8 @@ func (bt *BTServer) configure(ctx context.Context) {
|
|||||||
log.Println("Set listen port", settings.BTsets.PeersListenPort)
|
log.Println("Set listen port", settings.BTsets.PeersListenPort)
|
||||||
bt.config.ListenPort = settings.BTsets.PeersListenPort
|
bt.config.ListenPort = settings.BTsets.PeersListenPort
|
||||||
} else {
|
} else {
|
||||||
// lport := 32000
|
|
||||||
// for {
|
|
||||||
// log.Println("Check listen port", lport)
|
|
||||||
// l, err := net.Listen("tcp", ":"+strconv.Itoa(lport))
|
|
||||||
// if l != nil {
|
|
||||||
// l.Close()
|
|
||||||
// }
|
|
||||||
// if err == nil {
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// lport++
|
|
||||||
// }
|
|
||||||
// log.Println("Set listen port", lport)
|
|
||||||
log.Println("Set listen port to random autoselect (0)")
|
log.Println("Set listen port to random autoselect (0)")
|
||||||
bt.config.ListenPort = 0 // lport
|
bt.config.ListenPort = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,10 +186,11 @@ func (bt *BTServer) ListTorrents() map[metainfo.Hash]*Torrent {
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) {
|
func (bt *BTServer) RemoveTorrent(hash torrent.InfoHash) bool {
|
||||||
if torr, ok := bt.torrents[hash]; ok {
|
if torr, ok := bt.torrents[hash]; ok {
|
||||||
torr.Close()
|
return torr.Close()
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPrivateIP(ip net.IP) bool {
|
func isPrivateIP(ip net.IP) bool {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (t *Torrent) Preload(index int, size int64) {
|
|||||||
// Запуск лога в отдельном потоке
|
// Запуск лога в отдельном потоке
|
||||||
go func() {
|
go func() {
|
||||||
for t.Stat == state.TorrentPreload {
|
for t.Stat == state.TorrentPreload {
|
||||||
stat := fmt.Sprint(file.Torrent().InfoHash().HexString(), " ", utils2.Format(float64(t.PreloadedBytes)), "/", utils2.Format(float64(t.PreloadSize)), " Speed:", utils2.Format(t.DownloadSpeed), " Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
|
stat := fmt.Sprint(file.Torrent().InfoHash().HexString(), " ", utils2.Format(float64(t.PreloadedBytes)), "/", utils2.Format(float64(t.PreloadSize)), " Speed:", utils2.Format(t.DownloadSpeed), " Peers:", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers, " [Seeds:", t.Torrent.Stats().ConnectedSeeders, "]")
|
||||||
log.TLogln("Preload:", stat)
|
log.TLogln("Preload:", stat)
|
||||||
t.AddExpiredTime(time.Second * time.Duration(settings.BTsets.TorrentDisconnectTimeout))
|
t.AddExpiredTime(time.Second * time.Duration(settings.BTsets.TorrentDisconnectTimeout))
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@@ -158,7 +158,7 @@ func (t *Torrent) Preload(index int, size int64) {
|
|||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
log.TLogln("End preload:", file.Torrent().InfoHash().HexString(), "Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
|
log.TLogln("End preload:", file.Torrent().InfoHash().HexString(), "Peers:", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers, "[ Seeds:", t.Torrent.Stats().ConnectedSeeders, "]")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) findFileIndex(index int) *torrent.File {
|
func (t *Torrent) findFileIndex(index int) *torrent.File {
|
||||||
|
|||||||
@@ -314,6 +314,21 @@ func (c *Cache) NewReader(file *torrent.File) *Reader {
|
|||||||
return newReader(file, c)
|
return newReader(file, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Cache) GetUseReaders() int {
|
||||||
|
if c == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
c.muReaders.Lock()
|
||||||
|
defer c.muReaders.Unlock()
|
||||||
|
readers := 0
|
||||||
|
for reader := range c.readers {
|
||||||
|
if reader.isUse {
|
||||||
|
readers++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return readers
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cache) Readers() int {
|
func (c *Cache) Readers() int {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -25,20 +25,20 @@ func NewStorage(capacity int64) *Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (ts.TorrentImpl, error) {
|
func (s *Storage) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (ts.TorrentImpl, error) {
|
||||||
// capFunc := func() (int64, bool) {
|
// capFunc := func() (int64, bool) { // NE
|
||||||
// return s.capacity, true
|
// return s.capacity, true // NE
|
||||||
// }
|
// } // NE
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
ch := NewCache(s.capacity, s)
|
ch := NewCache(s.capacity, s)
|
||||||
ch.Init(info, infoHash)
|
ch.Init(info, infoHash)
|
||||||
s.caches[infoHash] = ch
|
s.caches[infoHash] = ch
|
||||||
return ch, nil
|
return ch, nil // OE
|
||||||
// return ts.TorrentImpl{
|
// return ts.TorrentImpl{ // NE
|
||||||
// Piece: ch.Piece,
|
// Piece: ch.Piece, // NE
|
||||||
// Close: ch.Close,
|
// Close: ch.Close, // NE
|
||||||
// Capacity: &capFunc,
|
// Capacity: &capFunc, // NE
|
||||||
// }, nil
|
// }, nil // NE
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) CloseHash(hash metainfo.Hash) {
|
func (s *Storage) CloseHash(hash metainfo.Hash) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/anacrolix/dms/dlna"
|
"github.com/anacrolix/dms/dlna"
|
||||||
"github.com/anacrolix/missinggo/httptoo"
|
"github.com/anacrolix/missinggo/v2/httptoo"
|
||||||
"github.com/anacrolix/torrent"
|
"github.com/anacrolix/torrent"
|
||||||
|
|
||||||
mt "server/mimetype"
|
mt "server/mimetype"
|
||||||
@@ -47,6 +47,10 @@ func (t *Torrent) Stream(fileID int, req *http.Request, resp http.ResponseWriter
|
|||||||
if file == nil {
|
if file == nil {
|
||||||
return fmt.Errorf("file with id %v not found", fileID)
|
return fmt.Errorf("file with id %v not found", fileID)
|
||||||
}
|
}
|
||||||
|
if int64(sets.MaxSize) > 0 && file.Length() > int64(sets.MaxSize) {
|
||||||
|
log.Println("file", file.DisplayPath(), "size exceeded max allowed", sets.MaxSize, "bytes")
|
||||||
|
return fmt.Errorf("file size exceeded max allowed %d bytes", sets.MaxSize)
|
||||||
|
}
|
||||||
|
|
||||||
reader := t.NewReader(file)
|
reader := t.NewReader(file)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
utils2 "server/utils"
|
||||||
|
|
||||||
"github.com/anacrolix/torrent"
|
"github.com/anacrolix/torrent"
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
|
|
||||||
@@ -266,7 +268,10 @@ func (t *Torrent) drop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) Close() {
|
func (t *Torrent) Close() bool {
|
||||||
|
if t.cache != nil && t.cache.GetUseReaders() > 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
t.Stat = state.TorrentClosed
|
t.Stat = state.TorrentClosed
|
||||||
|
|
||||||
t.bt.mu.Lock()
|
t.bt.mu.Lock()
|
||||||
@@ -274,6 +279,7 @@ func (t *Torrent) Close() {
|
|||||||
t.bt.mu.Unlock()
|
t.bt.mu.Unlock()
|
||||||
|
|
||||||
t.drop()
|
t.drop()
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) Status() *state.TorrentStatus {
|
func (t *Torrent) Status() *state.TorrentStatus {
|
||||||
@@ -329,7 +335,7 @@ func (t *Torrent) Status() *state.TorrentStatus {
|
|||||||
|
|
||||||
files := t.Files()
|
files := t.Files()
|
||||||
sort.Slice(files, func(i, j int) bool {
|
sort.Slice(files, func(i, j int) bool {
|
||||||
return files[i].Path() < files[j].Path()
|
return utils2.CompareStrings(files[i].Path(), files[j].Path())
|
||||||
})
|
})
|
||||||
for i, f := range files {
|
for i, f := range files {
|
||||||
st.FileStats = append(st.FileStats, &state.TorrentFileStat{
|
st.FileStats = append(st.FileStats, &state.TorrentFileStat{
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -46,3 +48,52 @@ func Format(b float64) string {
|
|||||||
|
|
||||||
return fmt.Sprintf("%.2f%s", value, multiple)
|
return fmt.Sprintf("%.2f%s", value, multiple)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CommonPrefix(first, second string) string {
|
||||||
|
var result strings.Builder
|
||||||
|
|
||||||
|
minLength := len(first)
|
||||||
|
if len(second) < minLength {
|
||||||
|
minLength = len(second)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < minLength; i++ {
|
||||||
|
if first[i] != second[i] {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result.WriteByte(first[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NumberPrefix(str string) (int, error) {
|
||||||
|
var result strings.Builder
|
||||||
|
|
||||||
|
for i := 0; i < len(str); i++ {
|
||||||
|
if !unicode.IsDigit(rune(str[i])) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result.WriteByte(str[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return strconv.Atoi(result.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompareStrings(first, second string) bool {
|
||||||
|
commonPrefix := CommonPrefix(first, second)
|
||||||
|
resultStr1 := strings.TrimPrefix(first, commonPrefix)
|
||||||
|
resultStr2 := strings.TrimPrefix(second, commonPrefix)
|
||||||
|
num1, err1 := NumberPrefix(resultStr1)
|
||||||
|
num2, err2 := NumberPrefix(resultStr2)
|
||||||
|
|
||||||
|
if err1 == nil && err2 == nil {
|
||||||
|
return num1 < num2
|
||||||
|
}
|
||||||
|
if err1 == nil {
|
||||||
|
return true
|
||||||
|
} else if err2 == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return resultStr1 < resultStr2
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
// "github.com/anacrolix/torrent"
|
// "github.com/anacrolix/torrent"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Version = "MatriX.127.2"
|
const Version = "MatriX.130"
|
||||||
|
|
||||||
func GetTorrentVersion() string {
|
func GetTorrentVersion() string {
|
||||||
bi, ok := debug.ReadBuildInfo()
|
bi, ok := debug.ReadBuildInfo()
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func (f *fileReader) Seek(offset int64, whence int) (int64, error) {
|
|||||||
//
|
//
|
||||||
// @Tags API
|
// @Tags API
|
||||||
//
|
//
|
||||||
// @Param size path string true "Test file size"
|
// @Param size path string true "Test file size (in MB)"
|
||||||
//
|
//
|
||||||
// @Produce application/octet-stream
|
// @Produce application/octet-stream
|
||||||
// @Success 200 {file} file
|
// @Success 200 {file} file
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ import (
|
|||||||
//
|
//
|
||||||
// @Tags API
|
// @Tags API
|
||||||
//
|
//
|
||||||
// @Param hash query string true "Torrent hash"
|
// @Param hash path string true "Torrent hash"
|
||||||
// @Param id query string true "File index in torrent"
|
// @Param id path string true "File index in torrent"
|
||||||
//
|
//
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 "Data returned from ffprobe"
|
// @Success 200 "Data returned from ffprobe"
|
||||||
// @Router /ffp [get]
|
// @Router /ffp/{hash}/{id} [get]
|
||||||
func ffp(c *gin.Context) {
|
func ffp(c *gin.Context) {
|
||||||
hash := c.Param("hash")
|
hash := c.Param("hash")
|
||||||
indexStr := c.Param("id")
|
indexStr := c.Param("id")
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/anacrolix/missinggo/httptoo"
|
"github.com/anacrolix/missinggo/v2/httptoo"
|
||||||
|
|
||||||
sets "server/settings"
|
sets "server/settings"
|
||||||
"server/torr"
|
"server/torr"
|
||||||
|
|||||||
@@ -19,17 +19,16 @@ import (
|
|||||||
//
|
//
|
||||||
// @Tags API
|
// @Tags API
|
||||||
//
|
//
|
||||||
// @Param hash query string true "Torrent hash"
|
// @Param hash path string true "Torrent hash"
|
||||||
// @Param id query string true "File index in torrent"
|
// @Param id path string true "File index in torrent"
|
||||||
// @Param not_auth query bool false "Not authenticated"
|
|
||||||
//
|
//
|
||||||
// @Produce application/octet-stream
|
// @Produce application/octet-stream
|
||||||
// @Success 200 "Torrent data"
|
// @Success 200 "Torrent data"
|
||||||
// @Router /play [get]
|
// @Router /play/{hash}/{id} [get]
|
||||||
func play(c *gin.Context) {
|
func play(c *gin.Context) {
|
||||||
hash := c.Param("hash")
|
hash := c.Param("hash")
|
||||||
indexStr := c.Param("id")
|
indexStr := c.Param("id")
|
||||||
notAuth := c.GetBool("not_auth")
|
notAuth := c.GetBool("auth_required") && c.GetString(gin.AuthUserKey) == ""
|
||||||
|
|
||||||
if hash == "" || indexStr == "" {
|
if hash == "" || indexStr == "" {
|
||||||
c.AbortWithError(http.StatusNotFound, errors.New("link should not be empty"))
|
c.AbortWithError(http.StatusNotFound, errors.New("link should not be empty"))
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
config "server/settings"
|
||||||
|
"server/web/auth"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -8,15 +11,17 @@ type requestI struct {
|
|||||||
Action string `json:"action,omitempty"`
|
Action string `json:"action,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupRoute(route *gin.RouterGroup) {
|
func SetupRoute(route gin.IRouter) {
|
||||||
route.GET("/shutdown", shutdown)
|
authorized := route.Group("/", auth.CheckAuth())
|
||||||
|
|
||||||
route.POST("/settings", settings)
|
authorized.GET("/shutdown", shutdown)
|
||||||
|
|
||||||
route.POST("/torrents", torrents)
|
authorized.POST("/settings", settings)
|
||||||
route.POST("/torrent/upload", torrentUpload)
|
|
||||||
|
|
||||||
route.POST("/cache", cache)
|
authorized.POST("/torrents", torrents)
|
||||||
|
authorized.POST("/torrent/upload", torrentUpload)
|
||||||
|
|
||||||
|
authorized.POST("/cache", cache)
|
||||||
|
|
||||||
route.HEAD("/stream", stream)
|
route.HEAD("/stream", stream)
|
||||||
route.HEAD("/stream/*fname", stream)
|
route.HEAD("/stream/*fname", stream)
|
||||||
@@ -27,15 +32,19 @@ func SetupRoute(route *gin.RouterGroup) {
|
|||||||
route.HEAD("/play/:hash/:id", play)
|
route.HEAD("/play/:hash/:id", play)
|
||||||
route.GET("/play/:hash/:id", play)
|
route.GET("/play/:hash/:id", play)
|
||||||
|
|
||||||
route.POST("/viewed", viewed)
|
authorized.POST("/viewed", viewed)
|
||||||
|
|
||||||
route.GET("/playlistall/all.m3u", allPlayList)
|
authorized.GET("/playlistall/all.m3u", allPlayList)
|
||||||
route.GET("/playlist", playList)
|
route.GET("/playlist", playList)
|
||||||
route.GET("/playlist/*fname", playList) // Is this endpoint still needed ? `fname` is never used in handler
|
route.GET("/playlist/*fname", playList) // Is this endpoint still needed ? `fname` is never used in handler
|
||||||
|
|
||||||
route.GET("/download/:size", download)
|
authorized.GET("/download/:size", download)
|
||||||
|
|
||||||
route.GET("/search/*query", rutorSearch)
|
if config.SearchWA {
|
||||||
|
route.GET("/search/*query", rutorSearch)
|
||||||
|
} else {
|
||||||
|
authorized.GET("/search/*query", rutorSearch)
|
||||||
|
}
|
||||||
|
|
||||||
route.GET("/ffp/:hash/:id", ffp)
|
authorized.GET("/ffp/:hash/:id", ffp)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,10 @@ import (
|
|||||||
// @Param stat query string false "Get statistics from torrent"
|
// @Param stat query string false "Get statistics from torrent"
|
||||||
// @Param save query string false "Should save torrent"
|
// @Param save query string false "Should save torrent"
|
||||||
// @Param m3u query string false "Get torrent as M3U playlist"
|
// @Param m3u query string false "Get torrent as M3U playlist"
|
||||||
// @Param fromlast query string false "Get m3u from last play"
|
// @Param fromlast query string false "Get M3U from last played file"
|
||||||
// @Param play query string false "Start stream torrent"
|
// @Param play query string false "Start stream torrent"
|
||||||
// @Param title query string true "Set title of torrent"
|
// @Param title query string true "Set title of torrent"
|
||||||
// @Param poster query string true "File index in torrent"
|
// @Param poster query string true "Set poster link of torrent"
|
||||||
// @Param not_auth query string true "Set poster link of torrent"
|
|
||||||
//
|
//
|
||||||
// @Produce application/octet-stream
|
// @Produce application/octet-stream
|
||||||
// @Success 200 "Data returned according to query"
|
// @Success 200 "Data returned according to query"
|
||||||
@@ -62,7 +61,7 @@ func stream(c *gin.Context) {
|
|||||||
title := c.Query("title")
|
title := c.Query("title")
|
||||||
poster := c.Query("poster")
|
poster := c.Query("poster")
|
||||||
data := ""
|
data := ""
|
||||||
notAuth := c.GetBool("not_auth")
|
notAuth := c.GetBool("auth_required") && c.GetString(gin.AuthUserKey) == ""
|
||||||
|
|
||||||
if notAuth && (play || m3u) {
|
if notAuth && (play || m3u) {
|
||||||
streamNoAuth(c)
|
streamNoAuth(c)
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ func torrents(c *gin.Context) {
|
|||||||
{
|
{
|
||||||
dropTorrent(req, c)
|
dropTorrent(req, c)
|
||||||
}
|
}
|
||||||
|
case "wipe":
|
||||||
|
{
|
||||||
|
wipeTorrents(req, c)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,3 +192,16 @@ func dropTorrent(req torrReqJS, c *gin.Context) {
|
|||||||
torr.DropTorrent(req.Hash)
|
torr.DropTorrent(req.Hash)
|
||||||
c.Status(200)
|
c.Status(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wipeTorrents(req torrReqJS, c *gin.Context) {
|
||||||
|
torrents := torr.ListTorrent()
|
||||||
|
for _, t := range torrents {
|
||||||
|
torr.RemTorrent(t.TorrentSpec.InfoHash.HexString())
|
||||||
|
}
|
||||||
|
// TODO: remove (copied todo from remTorrent())
|
||||||
|
if set.BTsets.EnableDLNA {
|
||||||
|
dlna.Stop()
|
||||||
|
dlna.Start()
|
||||||
|
}
|
||||||
|
c.Status(200)
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -16,15 +14,15 @@ import (
|
|||||||
"server/settings"
|
"server/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetupAuth(engine *gin.Engine) *gin.RouterGroup {
|
func SetupAuth(engine *gin.Engine) {
|
||||||
if !settings.HttpAuth {
|
if !settings.HttpAuth {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
accs := getAccounts()
|
accs := getAccounts()
|
||||||
if accs == nil {
|
if accs == nil {
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
return engine.Group("/", BasicAuth(accs))
|
engine.Use(BasicAuth(accs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAccounts() gin.Accounts {
|
func getAccounts() gin.Accounts {
|
||||||
@@ -61,21 +59,27 @@ func (a authPairs) searchCredential(authValue string) (string, bool) {
|
|||||||
func BasicAuth(accounts gin.Accounts) gin.HandlerFunc {
|
func BasicAuth(accounts gin.Accounts) gin.HandlerFunc {
|
||||||
pairs := processAccounts(accounts)
|
pairs := processAccounts(accounts)
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
c.Set("auth_required", true)
|
||||||
|
|
||||||
user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
|
user, found := pairs.searchCredential(c.Request.Header.Get("Authorization"))
|
||||||
if !found { // always accessible
|
if found {
|
||||||
if strings.HasPrefix(c.FullPath(), "/stream") ||
|
c.Set(gin.AuthUserKey, user)
|
||||||
c.FullPath() == "/site.webmanifest" ||
|
}
|
||||||
// https://github.com/YouROK/TorrServer/issues/172
|
}
|
||||||
(strings.HasPrefix(c.FullPath(), "/play") && c.FullPath() != "/playlistall/all.m3u") ||
|
}
|
||||||
(settings.SearchWA && strings.HasPrefix(c.FullPath(), "/search")) {
|
|
||||||
c.Set("not_auth", true)
|
func CheckAuth() gin.HandlerFunc {
|
||||||
return
|
return func(c *gin.Context) {
|
||||||
}
|
if !settings.HttpAuth {
|
||||||
c.Header("WWW-Authenticate", "Basic realm=Authorization Required")
|
|
||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Set(gin.AuthUserKey, user)
|
|
||||||
|
if _, ok := c.Get(gin.AuthUserKey); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("WWW-Authenticate", "Basic realm=Authorization Required")
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,8 +101,5 @@ func authorizationHeader(user, password string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func StringToBytes(s string) (b []byte) {
|
func StringToBytes(s string) (b []byte) {
|
||||||
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
|
return unsafe.Slice(unsafe.StringData(s), len(s))
|
||||||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
|
||||||
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"server/version"
|
"server/version"
|
||||||
|
"server/web/auth"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -30,10 +31,12 @@ func asset(c *gin.Context, t string, d []byte) {
|
|||||||
c.Data(200, t+"; charset=UTF-8", d)
|
c.Data(200, t+"; charset=UTF-8", d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupRoute(r *gin.RouterGroup) {
|
func SetupRoute(r gin.IRouter) {
|
||||||
r.GET("/msx/:pth", msxPTH)
|
authorized := r.Group("/", auth.CheckAuth())
|
||||||
r.GET("/msx/imdb", msxIMDB)
|
|
||||||
r.GET("/msx/imdb/:id", msxIMDBID)
|
authorized.GET("/msx/:pth", msxPTH)
|
||||||
|
authorized.GET("/msx/imdb", msxIMDB)
|
||||||
|
authorized.GET("/msx/imdb/:id", msxIMDBID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// msxPTH godoc
|
// msxPTH godoc
|
||||||
@@ -43,11 +46,11 @@ func SetupRoute(r *gin.RouterGroup) {
|
|||||||
//
|
//
|
||||||
// @Tags MSX
|
// @Tags MSX
|
||||||
//
|
//
|
||||||
// @Param link query string true "Magnet/hash/link to torrent"
|
// @Param link path string true "Route MSX pages"
|
||||||
//
|
//
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 "Data returned according to query"
|
// @Success 200 "Data returned according to path"
|
||||||
// @Router /msx [get]
|
// @Router /msx/{pth} [get]
|
||||||
func msxPTH(c *gin.Context) {
|
func msxPTH(c *gin.Context) {
|
||||||
js := []string{"http://msx.benzac.de/js/tvx-plugin.min.js"}
|
js := []string{"http://msx.benzac.de/js/tvx-plugin.min.js"}
|
||||||
switch p := c.Param("pth"); p {
|
switch p := c.Param("pth"); p {
|
||||||
@@ -114,7 +117,7 @@ func msxIMDB(c *gin.Context) {
|
|||||||
//
|
//
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 "JSON MSX IMDB informations"
|
// @Success 200 "JSON MSX IMDB informations"
|
||||||
// @Router /msx/imdb/:id [get]
|
// @Router /msx/imdb/{id} [get]
|
||||||
func msxIMDBID(c *gin.Context) {
|
func msxIMDBID(c *gin.Context) {
|
||||||
idb.Lock()
|
idb.Lock()
|
||||||
defer idb.Unlock()
|
defer idb.Unlock()
|
||||||
|
|||||||
@@ -6,13 +6,27 @@ import (
|
|||||||
|
|
||||||
"server/settings"
|
"server/settings"
|
||||||
"server/torr"
|
"server/torr"
|
||||||
|
"server/web/auth"
|
||||||
"server/web/pages/template"
|
"server/web/pages/template"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetupRoute(route *gin.RouterGroup) {
|
func SetupRoute(route gin.IRouter) {
|
||||||
template.RouteWebPages(route)
|
authorized := route.Group("/", auth.CheckAuth())
|
||||||
route.GET("/stat", statPage)
|
|
||||||
route.GET("/magnets", getTorrents)
|
webPagesAuth := route.Group("/", func() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
if slices.Contains([]string{"/site.webmanifest"}, c.FullPath()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
auth.CheckAuth()(c)
|
||||||
|
}
|
||||||
|
}())
|
||||||
|
|
||||||
|
template.RouteWebPages(webPagesAuth)
|
||||||
|
authorized.GET("/stat", statPage)
|
||||||
|
authorized.GET("/magnets", getTorrents)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stat godoc
|
// stat godoc
|
||||||
|
|||||||
@@ -118,20 +118,20 @@ var Mstile150x150png []byte
|
|||||||
//go:embed pages/site.webmanifest
|
//go:embed pages/site.webmanifest
|
||||||
var Sitewebmanifest []byte
|
var Sitewebmanifest []byte
|
||||||
|
|
||||||
//go:embed pages/static/js/2.41a752aa.chunk.js
|
//go:embed pages/static/js/2.916c2545.chunk.js
|
||||||
var Staticjs241a752aachunkjs []byte
|
var Staticjs2916c2545chunkjs []byte
|
||||||
|
|
||||||
//go:embed pages/static/js/2.41a752aa.chunk.js.LICENSE.txt
|
//go:embed pages/static/js/2.916c2545.chunk.js.LICENSE.txt
|
||||||
var Staticjs241a752aachunkjsLICENSEtxt []byte
|
var Staticjs2916c2545chunkjsLICENSEtxt []byte
|
||||||
|
|
||||||
//go:embed pages/static/js/2.41a752aa.chunk.js.map
|
//go:embed pages/static/js/2.916c2545.chunk.js.map
|
||||||
var Staticjs241a752aachunkjsmap []byte
|
var Staticjs2916c2545chunkjsmap []byte
|
||||||
|
|
||||||
//go:embed pages/static/js/main.b1d76117.chunk.js
|
//go:embed pages/static/js/main.55f380e1.chunk.js
|
||||||
var Staticjsmainb1d76117chunkjs []byte
|
var Staticjsmain55f380e1chunkjs []byte
|
||||||
|
|
||||||
//go:embed pages/static/js/main.b1d76117.chunk.js.map
|
//go:embed pages/static/js/main.55f380e1.chunk.js.map
|
||||||
var Staticjsmainb1d76117chunkjsmap []byte
|
var Staticjsmain55f380e1chunkjsmap []byte
|
||||||
|
|
||||||
//go:embed pages/static/js/runtime-main.f542387e.js
|
//go:embed pages/static/js/runtime-main.f542387e.js
|
||||||
var Staticjsruntimemainf542387ejs []byte
|
var Staticjsruntimemainf542387ejs []byte
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.js": "/static/js/main.b1d76117.chunk.js",
|
"main.js": "/static/js/main.55f380e1.chunk.js",
|
||||||
"main.js.map": "/static/js/main.b1d76117.chunk.js.map",
|
"main.js.map": "/static/js/main.55f380e1.chunk.js.map",
|
||||||
"runtime-main.js": "/static/js/runtime-main.f542387e.js",
|
"runtime-main.js": "/static/js/runtime-main.f542387e.js",
|
||||||
"runtime-main.js.map": "/static/js/runtime-main.f542387e.js.map",
|
"runtime-main.js.map": "/static/js/runtime-main.f542387e.js.map",
|
||||||
"static/js/2.41a752aa.chunk.js": "/static/js/2.41a752aa.chunk.js",
|
"static/js/2.916c2545.chunk.js": "/static/js/2.916c2545.chunk.js",
|
||||||
"static/js/2.41a752aa.chunk.js.map": "/static/js/2.41a752aa.chunk.js.map",
|
"static/js/2.916c2545.chunk.js.map": "/static/js/2.916c2545.chunk.js.map",
|
||||||
"index.html": "/index.html",
|
"index.html": "/index.html",
|
||||||
"static/js/2.41a752aa.chunk.js.LICENSE.txt": "/static/js/2.41a752aa.chunk.js.LICENSE.txt"
|
"static/js/2.916c2545.chunk.js.LICENSE.txt": "/static/js/2.916c2545.chunk.js.LICENSE.txt"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/js/runtime-main.f542387e.js",
|
"static/js/runtime-main.f542387e.js",
|
||||||
"static/js/2.41a752aa.chunk.js",
|
"static/js/2.916c2545.chunk.js",
|
||||||
"static/js/main.b1d76117.chunk.js"
|
"static/js/main.55f380e1.chunk.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,191 +1,331 @@
|
|||||||
package template
|
package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RouteWebPages(route *gin.RouterGroup) {
|
func RouteWebPages(route gin.IRouter) {
|
||||||
route.GET("/", func(c *gin.Context) {
|
route.GET("/", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Indexhtml))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "text/html; charset=utf-8", Indexhtml)
|
c.Data(200, "text/html; charset=utf-8", Indexhtml)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1125-2436.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1125-2436.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash11252436jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash11252436jpg)
|
c.Data(200, "image/jpeg", Applesplash11252436jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1136-640.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1136-640.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash1136640jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash1136640jpg)
|
c.Data(200, "image/jpeg", Applesplash1136640jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1170-2532.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1170-2532.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash11702532jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash11702532jpg)
|
c.Data(200, "image/jpeg", Applesplash11702532jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1242-2208.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1242-2208.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash12422208jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash12422208jpg)
|
c.Data(200, "image/jpeg", Applesplash12422208jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1242-2688.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1242-2688.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash12422688jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash12422688jpg)
|
c.Data(200, "image/jpeg", Applesplash12422688jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1284-2778.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1284-2778.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash12842778jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash12842778jpg)
|
c.Data(200, "image/jpeg", Applesplash12842778jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1334-750.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1334-750.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash1334750jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash1334750jpg)
|
c.Data(200, "image/jpeg", Applesplash1334750jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1536-2048.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1536-2048.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash15362048jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash15362048jpg)
|
c.Data(200, "image/jpeg", Applesplash15362048jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1620-2160.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1620-2160.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash16202160jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash16202160jpg)
|
c.Data(200, "image/jpeg", Applesplash16202160jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1668-2224.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1668-2224.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash16682224jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash16682224jpg)
|
c.Data(200, "image/jpeg", Applesplash16682224jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1668-2388.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1668-2388.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash16682388jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash16682388jpg)
|
c.Data(200, "image/jpeg", Applesplash16682388jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-1792-828.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-1792-828.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash1792828jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash1792828jpg)
|
c.Data(200, "image/jpeg", Applesplash1792828jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2048-1536.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2048-1536.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash20481536jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash20481536jpg)
|
c.Data(200, "image/jpeg", Applesplash20481536jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2048-2732.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2048-2732.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash20482732jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash20482732jpg)
|
c.Data(200, "image/jpeg", Applesplash20482732jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2160-1620.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2160-1620.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash21601620jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash21601620jpg)
|
c.Data(200, "image/jpeg", Applesplash21601620jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2208-1242.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2208-1242.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash22081242jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash22081242jpg)
|
c.Data(200, "image/jpeg", Applesplash22081242jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2224-1668.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2224-1668.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash22241668jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash22241668jpg)
|
c.Data(200, "image/jpeg", Applesplash22241668jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2388-1668.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2388-1668.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash23881668jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash23881668jpg)
|
c.Data(200, "image/jpeg", Applesplash23881668jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2436-1125.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2436-1125.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash24361125jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash24361125jpg)
|
c.Data(200, "image/jpeg", Applesplash24361125jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2532-1170.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2532-1170.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash25321170jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash25321170jpg)
|
c.Data(200, "image/jpeg", Applesplash25321170jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2688-1242.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2688-1242.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash26881242jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash26881242jpg)
|
c.Data(200, "image/jpeg", Applesplash26881242jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2732-2048.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2732-2048.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash27322048jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash27322048jpg)
|
c.Data(200, "image/jpeg", Applesplash27322048jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-2778-1284.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-2778-1284.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash27781284jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash27781284jpg)
|
c.Data(200, "image/jpeg", Applesplash27781284jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-640-1136.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-640-1136.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash6401136jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash6401136jpg)
|
c.Data(200, "image/jpeg", Applesplash6401136jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-750-1334.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-750-1334.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash7501334jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash7501334jpg)
|
c.Data(200, "image/jpeg", Applesplash7501334jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/apple-splash-828-1792.jpg", func(c *gin.Context) {
|
route.GET("/apple-splash-828-1792.jpg", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Applesplash8281792jpg))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/jpeg", Applesplash8281792jpg)
|
c.Data(200, "image/jpeg", Applesplash8281792jpg)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/asset-manifest.json", func(c *gin.Context) {
|
route.GET("/asset-manifest.json", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Assetmanifestjson))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "application/json", Assetmanifestjson)
|
c.Data(200, "application/json", Assetmanifestjson)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/browserconfig.xml", func(c *gin.Context) {
|
route.GET("/browserconfig.xml", func(c *gin.Context) {
|
||||||
c.Data(200, "text/xml; charset=utf-8", Browserconfigxml)
|
etag := fmt.Sprintf("%x", md5.Sum(Browserconfigxml))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "application/xml; charset=utf-8", Browserconfigxml)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/dlnaicon-120.png", func(c *gin.Context) {
|
route.GET("/dlnaicon-120.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Dlnaicon120png))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Dlnaicon120png)
|
c.Data(200, "image/png", Dlnaicon120png)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/dlnaicon-48.png", func(c *gin.Context) {
|
route.GET("/dlnaicon-48.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Dlnaicon48png))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Dlnaicon48png)
|
c.Data(200, "image/png", Dlnaicon48png)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/favicon-16x16.png", func(c *gin.Context) {
|
route.GET("/favicon-16x16.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Favicon16x16png))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Favicon16x16png)
|
c.Data(200, "image/png", Favicon16x16png)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/favicon-32x32.png", func(c *gin.Context) {
|
route.GET("/favicon-32x32.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Favicon32x32png))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Favicon32x32png)
|
c.Data(200, "image/png", Favicon32x32png)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/favicon.ico", func(c *gin.Context) {
|
route.GET("/favicon.ico", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Faviconico))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/vnd.microsoft.icon", Faviconico)
|
c.Data(200, "image/vnd.microsoft.icon", Faviconico)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/icon.png", func(c *gin.Context) {
|
route.GET("/icon.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Iconpng))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Iconpng)
|
c.Data(200, "image/png", Iconpng)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/index.html", func(c *gin.Context) {
|
route.GET("/index.html", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Indexhtml))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "text/html; charset=utf-8", Indexhtml)
|
c.Data(200, "text/html; charset=utf-8", Indexhtml)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/logo.png", func(c *gin.Context) {
|
route.GET("/logo.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Logopng))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Logopng)
|
c.Data(200, "image/png", Logopng)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/mstile-150x150.png", func(c *gin.Context) {
|
route.GET("/mstile-150x150.png", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Mstile150x150png))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "image/png", Mstile150x150png)
|
c.Data(200, "image/png", Mstile150x150png)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/site.webmanifest", func(c *gin.Context) {
|
route.GET("/site.webmanifest", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Sitewebmanifest))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "application/manifest+json", Sitewebmanifest)
|
c.Data(200, "application/manifest+json", Sitewebmanifest)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/2.41a752aa.chunk.js", func(c *gin.Context) {
|
route.GET("/static/js/2.916c2545.chunk.js", func(c *gin.Context) {
|
||||||
c.Data(200, "text/javascript; charset=utf-8", Staticjs241a752aachunkjs)
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjs2916c2545chunkjs))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "application/javascript; charset=utf-8", Staticjs2916c2545chunkjs)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/2.41a752aa.chunk.js.LICENSE.txt", func(c *gin.Context) {
|
route.GET("/static/js/2.916c2545.chunk.js.LICENSE.txt", func(c *gin.Context) {
|
||||||
c.Data(200, "text/plain; charset=utf-8", Staticjs241a752aachunkjsLICENSEtxt)
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjs2916c2545chunkjsLICENSEtxt))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "text/plain; charset=utf-8", Staticjs2916c2545chunkjsLICENSEtxt)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/2.41a752aa.chunk.js.map", func(c *gin.Context) {
|
route.GET("/static/js/2.916c2545.chunk.js.map", func(c *gin.Context) {
|
||||||
c.Data(200, "application/json", Staticjs241a752aachunkjsmap)
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjs2916c2545chunkjsmap))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "application/json", Staticjs2916c2545chunkjsmap)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/main.b1d76117.chunk.js", func(c *gin.Context) {
|
route.GET("/static/js/main.55f380e1.chunk.js", func(c *gin.Context) {
|
||||||
c.Data(200, "text/javascript; charset=utf-8", Staticjsmainb1d76117chunkjs)
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjsmain55f380e1chunkjs))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "application/javascript; charset=utf-8", Staticjsmain55f380e1chunkjs)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/main.b1d76117.chunk.js.map", func(c *gin.Context) {
|
route.GET("/static/js/main.55f380e1.chunk.js.map", func(c *gin.Context) {
|
||||||
c.Data(200, "application/json", Staticjsmainb1d76117chunkjsmap)
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjsmain55f380e1chunkjsmap))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "application/json", Staticjsmain55f380e1chunkjsmap)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/runtime-main.f542387e.js", func(c *gin.Context) {
|
route.GET("/static/js/runtime-main.f542387e.js", func(c *gin.Context) {
|
||||||
c.Data(200, "text/javascript; charset=utf-8", Staticjsruntimemainf542387ejs)
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjsruntimemainf542387ejs))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
|
c.Data(200, "application/javascript; charset=utf-8", Staticjsruntimemainf542387ejs)
|
||||||
})
|
})
|
||||||
|
|
||||||
route.GET("/static/js/runtime-main.f542387e.js.map", func(c *gin.Context) {
|
route.GET("/static/js/runtime-main.f542387e.js.map", func(c *gin.Context) {
|
||||||
|
etag := fmt.Sprintf("%x", md5.Sum(Staticjsruntimemainf542387ejsmap))
|
||||||
|
c.Header("Cache-Control", "public, max-age=31536000")
|
||||||
|
c.Header("ETag", etag)
|
||||||
c.Data(200, "application/json", Staticjsruntimemainf542387ejsmap)
|
c.Data(200, "application/json", Staticjsruntimemainf542387ejsmap)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,19 +71,14 @@ func Start() {
|
|||||||
|
|
||||||
route := gin.New()
|
route := gin.New()
|
||||||
route.Use(log.WebLogger(), blocker.Blocker(), gin.Recovery(), cors.New(corsCfg), location.Default())
|
route.Use(log.WebLogger(), blocker.Blocker(), gin.Recovery(), cors.New(corsCfg), location.Default())
|
||||||
|
auth.SetupAuth(route)
|
||||||
|
|
||||||
route.GET("/echo", echo)
|
route.GET("/echo", echo)
|
||||||
|
|
||||||
routeAuth := auth.SetupAuth(route)
|
api.SetupRoute(route)
|
||||||
if routeAuth != nil {
|
msx.SetupRoute(route)
|
||||||
api.SetupRoute(routeAuth)
|
pages.SetupRoute(route)
|
||||||
msx.SetupRoute(routeAuth)
|
|
||||||
pages.SetupRoute(routeAuth)
|
|
||||||
} else {
|
|
||||||
api.SetupRoute(&route.RouterGroup)
|
|
||||||
msx.SetupRoute(&route.RouterGroup)
|
|
||||||
pages.SetupRoute(&route.RouterGroup)
|
|
||||||
}
|
|
||||||
if settings.BTsets.EnableDLNA {
|
if settings.BTsets.EnableDLNA {
|
||||||
dlna.Start()
|
dlna.Start()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,13 +85,16 @@ export default function AboutDialog() {
|
|||||||
<LinkComponent name='tw1cker' link='https://github.com/Nemiroff' />
|
<LinkComponent name='tw1cker' link='https://github.com/Nemiroff' />
|
||||||
<LinkComponent name='SpAwN_LMG' link='https://github.com/spawnlmg' />
|
<LinkComponent name='SpAwN_LMG' link='https://github.com/spawnlmg' />
|
||||||
<LinkComponent name='damiva' link='https://github.com/damiva' />
|
<LinkComponent name='damiva' link='https://github.com/damiva' />
|
||||||
|
<LinkComponent name='Vladlenas' link='https://github.com/vladlenas' />
|
||||||
<LinkComponent name='Anton Potekhin' link='https://github.com/Anton111111' />
|
<LinkComponent name='Anton Potekhin' link='https://github.com/Anton111111' />
|
||||||
<LinkComponent name='FaintGhost' link='https://github.com/FaintGhost' />
|
<LinkComponent name='FaintGhost' link='https://github.com/FaintGhost' />
|
||||||
<LinkComponent name='TopperBG' link='https://github.com/TopperBG' />
|
<LinkComponent name='TopperBG' link='https://github.com/TopperBG' />
|
||||||
<LinkComponent name='FaintGhost' link='https://github.com/FaintGhost' />
|
<LinkComponent name='Evgeni' link='https://github.com/lieranderl' />
|
||||||
<LinkComponent name='lieranderl' link='https://github.com/lieranderl' />
|
|
||||||
<LinkComponent name='cocool97' link='https://github.com/cocool97' />
|
<LinkComponent name='cocool97' link='https://github.com/cocool97' />
|
||||||
<LinkComponent name='shadeov' link='https://github.com/shadeov' />
|
<LinkComponent name='shadeov' link='https://github.com/shadeov' />
|
||||||
|
<LinkComponent name='Pavel' link='https://github.com/butaford' />
|
||||||
|
<LinkComponent name='Alexey Filimonov' link='https://github.com/filimonic' />
|
||||||
|
<LinkComponent name='Viacheslav Evseev' link='https://github.com/leporel' />
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -39,7 +39,11 @@ export default function LeftSideComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [isTorrentSourceActive, setIsTorrentSourceActive] = useState(false)
|
const [isTorrentSourceActive, setIsTorrentSourceActive] = useState(false)
|
||||||
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop: handleCapture, accept: '.torrent' })
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
||||||
|
onDrop: handleCapture,
|
||||||
|
accept: '.torrent',
|
||||||
|
multiple: false,
|
||||||
|
})
|
||||||
|
|
||||||
const handleTorrentSourceChange = ({ target: { value } }) => setTorrentSource(value)
|
const handleTorrentSourceChange = ({ target: { value } }) => setTorrentSource(value)
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Button, DialogActions, DialogTitle, ListItemIcon, ListItemText } from '@material-ui/core'
|
import { Button, DialogActions, DialogTitle, ListItemIcon, ListItemText } from '@material-ui/core'
|
||||||
import { StyledDialog, StyledMenuButtonWrapper } from 'style/CustomMaterialUiStyles'
|
import { StyledDialog, StyledMenuButtonWrapper } from 'style/CustomMaterialUiStyles'
|
||||||
import { PowerSettingsNew as PowerSettingsNewIcon } from '@material-ui/icons'
|
import { PowerSettingsNew as PowerSettingsNewIcon, PowerOff as PowerOffIcon } from '@material-ui/icons'
|
||||||
import { shutdownHost } from 'utils/Hosts'
|
import { shutdownHost } from 'utils/Hosts'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { isStandaloneApp } from 'utils/Utils'
|
import { isStandaloneApp } from 'utils/Utils'
|
||||||
import useOnStandaloneAppOutsideClick from 'utils/useOnStandaloneAppOutsideClick'
|
import useOnStandaloneAppOutsideClick from 'utils/useOnStandaloneAppOutsideClick'
|
||||||
|
|
||||||
|
import UnsafeButton from './UnsafeButton'
|
||||||
|
|
||||||
export default function CloseServer({ isOffline, isLoading }) {
|
export default function CloseServer({ isOffline, isLoading }) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
@@ -41,7 +43,9 @@ export default function CloseServer({ isOffline, isLoading }) {
|
|||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<UnsafeButton
|
||||||
|
timeout={5}
|
||||||
|
startIcon={<PowerOffIcon />}
|
||||||
variant='contained'
|
variant='contained'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
fetch(shutdownHost())
|
fetch(shutdownHost())
|
||||||
@@ -51,7 +55,7 @@ export default function CloseServer({ isOffline, isLoading }) {
|
|||||||
autoFocus
|
autoFocus
|
||||||
>
|
>
|
||||||
{t('TurnOff')}
|
{t('TurnOff')}
|
||||||
</Button>
|
</UnsafeButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</StyledDialog>
|
</StyledDialog>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const playableExtList = [
|
|||||||
'avchd',
|
'avchd',
|
||||||
'avi',
|
'avi',
|
||||||
'drc',
|
'drc',
|
||||||
|
'dv',
|
||||||
'flv',
|
'flv',
|
||||||
'iso',
|
'iso',
|
||||||
'm2v',
|
'm2v',
|
||||||
@@ -27,9 +28,9 @@ const playableExtList = [
|
|||||||
'mpeg',
|
'mpeg',
|
||||||
'mpg',
|
'mpg',
|
||||||
'mpv',
|
'mpv',
|
||||||
|
'mts',
|
||||||
'mxf',
|
'mxf',
|
||||||
'nsv',
|
'nsv',
|
||||||
'ogg',
|
|
||||||
'ogv',
|
'ogv',
|
||||||
'ts',
|
'ts',
|
||||||
'qt',
|
'qt',
|
||||||
@@ -46,6 +47,9 @@ const playableExtList = [
|
|||||||
'aiff',
|
'aiff',
|
||||||
'ape',
|
'ape',
|
||||||
'au',
|
'au',
|
||||||
|
'dsd',
|
||||||
|
'dff',
|
||||||
|
'dsf',
|
||||||
'flac',
|
'flac',
|
||||||
'gsm',
|
'gsm',
|
||||||
'it',
|
'it',
|
||||||
@@ -55,11 +59,15 @@ const playableExtList = [
|
|||||||
'mod',
|
'mod',
|
||||||
'mp3',
|
'mp3',
|
||||||
'mpa',
|
'mpa',
|
||||||
|
'oga',
|
||||||
|
'ogg',
|
||||||
|
'opus',
|
||||||
'pls',
|
'pls',
|
||||||
'ra',
|
'ra',
|
||||||
's3m',
|
's3m',
|
||||||
'sid',
|
'sid',
|
||||||
'wav',
|
'wav',
|
||||||
|
'weba',
|
||||||
'wma',
|
'wma',
|
||||||
'xm',
|
'xm',
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export const PeersWidget = ({ data }) => {
|
|||||||
return (
|
return (
|
||||||
<StatisticsField
|
<StatisticsField
|
||||||
title={t('Peers')}
|
title={t('Peers')}
|
||||||
value={getPeerString(data) || '0 · 0 / 0'}
|
value={getPeerString(data) || '0 / 0 · 0'}
|
||||||
iconBg={iconBGColor}
|
iconBg={iconBGColor}
|
||||||
valueBg={valueBGColor}
|
valueBg={valueBGColor}
|
||||||
icon={SwapVerticalCircleIcon}
|
icon={SwapVerticalCircleIcon}
|
||||||
|
|||||||
@@ -7,28 +7,17 @@ import { useState } from 'react'
|
|||||||
import { torrentsHost } from 'utils/Hosts'
|
import { torrentsHost } from 'utils/Hosts'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import UnsafeButton from './UnsafeButton'
|
||||||
|
|
||||||
const fnRemoveAll = () => {
|
const fnRemoveAll = () => {
|
||||||
fetch(torrentsHost(), {
|
fetch(torrentsHost(), {
|
||||||
method: 'post',
|
method: 'post',
|
||||||
body: JSON.stringify({ action: 'list' }),
|
body: JSON.stringify({ action: 'wipe' }),
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json, text/plain, */*',
|
Accept: 'application/json, text/plain, */*',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(res => res.json())
|
|
||||||
.then(json => {
|
|
||||||
json.forEach(torr => {
|
|
||||||
fetch(torrentsHost(), {
|
|
||||||
method: 'post',
|
|
||||||
body: JSON.stringify({ action: 'rem', hash: torr.hash }),
|
|
||||||
headers: {
|
|
||||||
Accept: 'application/json, text/plain, */*',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RemoveAll({ isOffline, isLoading }) {
|
export default function RemoveAll({ isOffline, isLoading }) {
|
||||||
@@ -54,7 +43,9 @@ export default function RemoveAll({ isOffline, isLoading }) {
|
|||||||
{t('Cancel')}
|
{t('Cancel')}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<UnsafeButton
|
||||||
|
timeout={5}
|
||||||
|
startIcon={<DeleteIcon />}
|
||||||
variant='contained'
|
variant='contained'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
fnRemoveAll()
|
fnRemoveAll()
|
||||||
@@ -64,7 +55,7 @@ export default function RemoveAll({ isOffline, isLoading }) {
|
|||||||
autoFocus
|
autoFocus
|
||||||
>
|
>
|
||||||
{t('OK')}
|
{t('OK')}
|
||||||
</Button>
|
</UnsafeButton>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ export default function AddFirstTorrent() {
|
|||||||
<>
|
<>
|
||||||
<IconWrapper onClick={() => handleClickOpen(true)} isButton>
|
<IconWrapper onClick={() => handleClickOpen(true)} isButton>
|
||||||
<lord-icon
|
<lord-icon
|
||||||
src='https://cdn.lordicon.com/bbnkwdur.json'
|
src='https://cdn.lordicon.com/jkzgajyr.json'
|
||||||
trigger='loop'
|
trigger='loop'
|
||||||
colors={`primary:#121331,secondary:${primary}`}
|
delay='2000'
|
||||||
stroke='26'
|
colors={`primary:#575757,secondary:${primary}`}
|
||||||
|
stroke='light'
|
||||||
scale='60'
|
scale='60'
|
||||||
/>
|
/>
|
||||||
<div className='icon-label'>{t('NoTorrentsAdded')}</div>
|
<div className='icon-label'>{t('NoTorrentsAdded')}</div>
|
||||||
|
|||||||
29
web/src/components/UnsafeButton.jsx
Normal file
29
web/src/components/UnsafeButton.jsx
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Button } from '@material-ui/core'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
export default function UnsafeButton({ timeout, children, disabled, ...props }) {
|
||||||
|
const [timeLeft, setTimeLeft] = useState(timeout || 7)
|
||||||
|
const [buttonDisabled, setButtonDisabled] = useState(disabled || timeLeft > 0)
|
||||||
|
const handleTimerTick = () => {
|
||||||
|
const newTimeLeft = timeLeft - 1
|
||||||
|
setTimeLeft(newTimeLeft)
|
||||||
|
if (newTimeLeft <= 0) {
|
||||||
|
setButtonDisabled(disabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getTimerText = () => (!disabled && timeLeft > 0 ? ` (${timeLeft})` : '')
|
||||||
|
useEffect(() => {
|
||||||
|
if (disabled || !timeLeft) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const intervalId = setInterval(handleTimerTick, 1000)
|
||||||
|
return () => clearInterval(intervalId)
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, [timeLeft])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button disabled={buttonDisabled} {...props}>
|
||||||
|
{children} {getTimerText()}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"Offline": "Извън линия",
|
"Offline": "Извън линия",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"OpenLink": "Отвори линк",
|
"OpenLink": "Отвори линк",
|
||||||
"Peers": "Пиъри",
|
"Peers": "Пиъри·Сийдъри",
|
||||||
"PiecesCount": "Брой парчета",
|
"PiecesCount": "Брой парчета",
|
||||||
"PiecesLength": "Дължина на парчетата",
|
"PiecesLength": "Дължина на парчетата",
|
||||||
"Playlist": "Плейлист",
|
"Playlist": "Плейлист",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"Offline": "Offline",
|
"Offline": "Offline",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"OpenLink": "Open link",
|
"OpenLink": "Open link",
|
||||||
"Peers": "Peers",
|
"Peers": "Peers·Seeds",
|
||||||
"PiecesCount": "Pieces count",
|
"PiecesCount": "Pieces count",
|
||||||
"PiecesLength": "Pieces length",
|
"PiecesLength": "Pieces length",
|
||||||
"Playlist": "Playlist",
|
"Playlist": "Playlist",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"Offline": "Сервер недоступен",
|
"Offline": "Сервер недоступен",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"OpenLink": "Открыть",
|
"OpenLink": "Открыть",
|
||||||
"Peers": "Пиры",
|
"Peers": "Пиры·Сиды",
|
||||||
"PiecesCount": "Кол-во блоков",
|
"PiecesCount": "Кол-во блоков",
|
||||||
"PiecesLength": "Размер блока",
|
"PiecesLength": "Размер блока",
|
||||||
"Playlist": "Плейлист",
|
"Playlist": "Плейлист",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"Offline": "Сервер не доступний",
|
"Offline": "Сервер не доступний",
|
||||||
"OK": "OK",
|
"OK": "OK",
|
||||||
"OpenLink": "Відкрити",
|
"OpenLink": "Відкрити",
|
||||||
"Peers": "Піри",
|
"Peers": "Піри·Сіди",
|
||||||
"PiecesCount": "К-сть блоків",
|
"PiecesCount": "К-сть блоків",
|
||||||
"PiecesLength": "Розмір блоку",
|
"PiecesLength": "Розмір блоку",
|
||||||
"Playlist": "Плейлист",
|
"Playlist": "Плейлист",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"Offline": "离线",
|
"Offline": "离线",
|
||||||
"OK": "确定",
|
"OK": "确定",
|
||||||
"OpenLink": "打开链接",
|
"OpenLink": "打开链接",
|
||||||
"Peers": "Peers",
|
"Peers": "Peers·Seeds",
|
||||||
"PiecesCount": "块数量",
|
"PiecesCount": "块数量",
|
||||||
"PiecesLength": "块长度",
|
"PiecesLength": "块长度",
|
||||||
"Playlist": "播放列表",
|
"Playlist": "播放列表",
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ export function humanizeSpeed(speed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getPeerString(torrent) {
|
export function getPeerString(torrent) {
|
||||||
if (!torrent || !torrent.connected_seeders) return null
|
if (!torrent || !torrent.active_peers) return null
|
||||||
return `${torrent.connected_seeders} · ${torrent.active_peers} / ${torrent.total_peers}`
|
const seeders = typeof torrent.connected_seeders !== 'undefined' ? torrent.connected_seeders : 0
|
||||||
|
return `${torrent.active_peers} / ${torrent.total_peers} · ${seeders}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const shortenText = (text, sympolAmount) =>
|
export const shortenText = (text, sympolAmount) =>
|
||||||
|
|||||||
@@ -5230,13 +5230,14 @@ es-to-primitive@^1.2.1:
|
|||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50:
|
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.62, es5-ext@~0.10.14:
|
||||||
version "0.10.62"
|
version "0.10.63"
|
||||||
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5"
|
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
|
||||||
integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==
|
integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
es6-iterator "^2.0.3"
|
es6-iterator "^2.0.3"
|
||||||
es6-symbol "^3.1.3"
|
es6-symbol "^3.1.3"
|
||||||
|
esniff "^2.0.1"
|
||||||
next-tick "^1.1.0"
|
next-tick "^1.1.0"
|
||||||
|
|
||||||
es6-iterator@2.0.3, es6-iterator@^2.0.1, es6-iterator@^2.0.3:
|
es6-iterator@2.0.3, es6-iterator@^2.0.1, es6-iterator@^2.0.3:
|
||||||
@@ -5559,6 +5560,16 @@ eslint@^7.11.0, eslint@^7.27.0:
|
|||||||
text-table "^0.2.0"
|
text-table "^0.2.0"
|
||||||
v8-compile-cache "^2.0.3"
|
v8-compile-cache "^2.0.3"
|
||||||
|
|
||||||
|
esniff@^2.0.1:
|
||||||
|
version "2.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
|
||||||
|
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
|
||||||
|
dependencies:
|
||||||
|
d "^1.0.1"
|
||||||
|
es5-ext "^0.10.62"
|
||||||
|
event-emitter "^0.3.5"
|
||||||
|
type "^2.7.2"
|
||||||
|
|
||||||
espree@^7.3.0, espree@^7.3.1:
|
espree@^7.3.0, espree@^7.3.1:
|
||||||
version "7.3.1"
|
version "7.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
|
resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
|
||||||
@@ -5622,6 +5633,14 @@ etag@~1.8.1:
|
|||||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||||
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||||
|
|
||||||
|
event-emitter@^0.3.5:
|
||||||
|
version "0.3.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
|
||||||
|
integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==
|
||||||
|
dependencies:
|
||||||
|
d "1"
|
||||||
|
es5-ext "~0.10.14"
|
||||||
|
|
||||||
eventemitter3@^4.0.0:
|
eventemitter3@^4.0.0:
|
||||||
version "4.0.7"
|
version "4.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
||||||
@@ -6037,9 +6056,9 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
|
|||||||
readable-stream "^2.3.6"
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
follow-redirects@^1.0.0, follow-redirects@^1.15.0:
|
follow-redirects@^1.0.0, follow-redirects@^1.15.0:
|
||||||
version "1.15.3"
|
version "1.15.4"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
|
||||||
integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==
|
integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
|
||||||
|
|
||||||
for-each@^0.3.3:
|
for-each@^0.3.3:
|
||||||
version "0.3.3"
|
version "0.3.3"
|
||||||
@@ -7063,9 +7082,9 @@ ip-regex@^2.1.0:
|
|||||||
integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==
|
integrity sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==
|
||||||
|
|
||||||
ip@^1.1.0, ip@^1.1.5:
|
ip@^1.1.0, ip@^1.1.5:
|
||||||
version "1.1.8"
|
version "1.1.9"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.8.tgz#ae05948f6b075435ed3307acce04629da8cdbf48"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396"
|
||||||
integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==
|
integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==
|
||||||
|
|
||||||
ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
|
ipaddr.js@1.9.1, ipaddr.js@^1.9.0:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user