mirror of
https://github.com/simon-ding/polaris.git
synced 2026-02-22 19:50:57 +08:00
Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dea4ecb9d4 | ||
|
|
d15f04e69c | ||
|
|
3967e7b77d | ||
|
|
05d114be66 | ||
|
|
94b4db3310 | ||
|
|
e5261e7aac | ||
|
|
2778df89c6 | ||
|
|
a978ae4fba | ||
|
|
e27b327f93 | ||
|
|
96e6576f09 | ||
|
|
1ddba4ddce | ||
|
|
8ea5715ce4 | ||
|
|
03454543a3 | ||
|
|
8fdfbbd177 | ||
|
|
a169085504 | ||
|
|
60161f5c64 | ||
|
|
90e90cf288 | ||
|
|
c38c6dcf74 | ||
|
|
8b96e30115 | ||
|
|
0ae36d9c88 | ||
|
|
f24d6870de | ||
|
|
d265f17712 | ||
|
|
f6f9bb5e37 | ||
|
|
6f3da87bbc | ||
|
|
c2881627cc | ||
|
|
360a90414b | ||
|
|
294cd65ab2 | ||
|
|
720219433d | ||
|
|
002823492f | ||
|
|
65d58b2e84 | ||
|
|
1f92429fd3 | ||
|
|
9e00e69941 | ||
|
|
61c8023ff0 | ||
|
|
bc26d91792 | ||
|
|
d6d51d97d7 | ||
|
|
33b5f35bd2 | ||
|
|
d8a717798b | ||
|
|
932d6a88ac | ||
|
|
b15c761ceb | ||
|
|
55d786d285 | ||
|
|
9cb7460432 | ||
|
|
566dbc43d6 | ||
|
|
27fb5d3e13 | ||
|
|
d1137d2b06 | ||
|
|
19c6e7dd7b | ||
|
|
ee23bb2c3e | ||
|
|
8f3dab6728 | ||
|
|
4952422df7 | ||
|
|
ad950f6c28 | ||
|
|
068aa121a4 | ||
|
|
5e143edda3 | ||
|
|
a491a5f1ea | ||
|
|
094c7a24b9 | ||
|
|
b80d38788c | ||
|
|
f59a0682c6 | ||
|
|
ead022e17d | ||
|
|
b69100d9b4 | ||
|
|
bb0d5d1b58 | ||
|
|
992fa7ddd0 | ||
|
|
bb2c567da7 | ||
|
|
2dae168cb2 | ||
|
|
9719c6a7c9 | ||
|
|
5375f66018 | ||
|
|
3a73d0c33e | ||
|
|
3eb1f37387 | ||
|
|
9b791ba86f | ||
|
|
22db6b15cf | ||
|
|
33d82951c1 | ||
|
|
dd77e25b38 | ||
|
|
c58a038daf | ||
|
|
b81c5d327c | ||
|
|
04dcbf04e7 | ||
|
|
4bf72a7976 |
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gomod" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
||||
1
.github/workflows/goreleaser.yml
vendored
1
.github/workflows/goreleaser.yml
vendored
@@ -46,5 +46,6 @@ jobs:
|
||||
args: release --clean --skip=validate
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TMDB_API_KEY: ${{ secrets.TMDB_API_KEY }}
|
||||
# Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
|
||||
# GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -61,7 +61,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,linux/386,linux/s390x,linux/ppc64le
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
|
||||
@@ -23,7 +23,9 @@ builds:
|
||||
- windows
|
||||
- darwin
|
||||
- freebsd
|
||||
main: ./cmd
|
||||
main: ./cmd/polaris
|
||||
ldflags:
|
||||
- -X polaris/db.Version=$(git describe --tags --long) -X polaris/db.DefaultTmdbApiKey=$(echo $TMDB_API_KEY)
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
|
||||
2
Makefile
2
Makefile
@@ -2,5 +2,5 @@
|
||||
|
||||
windows:
|
||||
@echo "Building for Windows..."
|
||||
go build -tags c -ldflags="-X polaris/db.Version=$(git describe --tags --long)" -buildmode=c-shared -o ui/windows/libpolaris.dll ./cmd/binding
|
||||
go build -tags lib -ldflags="-X polaris/db.Version=$(git describe --tags --long)" -buildmode=c-shared -o ui/windows/libpolaris.dll ./cmd/binding
|
||||
cd ui && flutter build windows
|
||||
@@ -2,20 +2,45 @@ package main
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"os"
|
||||
"polaris/cmd"
|
||||
"polaris/db"
|
||||
"polaris/log"
|
||||
"polaris/server"
|
||||
)
|
||||
|
||||
func main() {}
|
||||
|
||||
var srv *server.Server
|
||||
var port int
|
||||
|
||||
//export Start
|
||||
func Start() {
|
||||
cmd.Start(true)
|
||||
func Start() (C.int, *C.char) {
|
||||
if srv != nil {
|
||||
return C.int(port), nil
|
||||
}
|
||||
log.InitLogger(true)
|
||||
|
||||
log.Infof("------------------- Starting Polaris ---------------------")
|
||||
dbClient, err := db.Open()
|
||||
if err != nil {
|
||||
log.Panicf("init db error: %v", err)
|
||||
return C.int(0), C.CString(err.Error())
|
||||
}
|
||||
|
||||
s := server.NewServer(dbClient)
|
||||
if p, err := s.Start(""); err != nil {
|
||||
return C.int(0), C.CString(err.Error())
|
||||
} else {
|
||||
port = p
|
||||
srv = s
|
||||
return C.int(p), C.CString("")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//export Stop
|
||||
func Stop() {
|
||||
log.Infof("stop polaris")
|
||||
os.Exit(0)
|
||||
if srv != nil {
|
||||
srv.Stop()
|
||||
}
|
||||
srv = nil
|
||||
}
|
||||
|
||||
26
cmd/doc.go
26
cmd/doc.go
@@ -1,27 +1 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"polaris/db"
|
||||
"polaris/log"
|
||||
"polaris/server"
|
||||
)
|
||||
|
||||
func Start(sharedLib bool) {
|
||||
if sharedLib || os.Getenv("GIN_MODE") == "release" {
|
||||
log.InitLogger(true)
|
||||
} else {
|
||||
log.InitLogger(false)
|
||||
}
|
||||
|
||||
log.Infof("------------------- Starting Polaris ---------------------")
|
||||
dbClient, err := db.Open()
|
||||
if err != nil {
|
||||
log.Panicf("init db error: %v", err)
|
||||
}
|
||||
|
||||
s := server.NewServer(dbClient)
|
||||
if err := s.Serve(); err != nil {
|
||||
log.Errorf("server start error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,35 @@
|
||||
package main
|
||||
|
||||
import "polaris/cmd"
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"polaris/db"
|
||||
"polaris/log"
|
||||
"polaris/pkg/utils"
|
||||
"polaris/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Start(false)
|
||||
}
|
||||
port := flag.Int("port", 3322, "port to listen on")
|
||||
flag.Parse()
|
||||
|
||||
if os.Getenv("GIN_MODE") == "release" {
|
||||
log.InitLogger(true)
|
||||
}
|
||||
|
||||
log.Infof("------------------- Starting Polaris ---------------------")
|
||||
dbClient, err := db.Open()
|
||||
if err != nil {
|
||||
log.Panicf("init db error: %v", err)
|
||||
}
|
||||
if !utils.IsRunningInDocker() {
|
||||
go utils.OpenURL(fmt.Sprintf("http://127.0.0.1:%d", *port))
|
||||
}
|
||||
|
||||
s := server.NewServer(dbClient)
|
||||
if _, err := s.Start(fmt.Sprintf(":%d", *port)); err != nil {
|
||||
log.Errorf("server start error: %v", err)
|
||||
}
|
||||
select {} //wait indefinitely
|
||||
}
|
||||
|
||||
18
db/const.go
18
db/const.go
@@ -1,9 +1,12 @@
|
||||
package db
|
||||
|
||||
import "polaris/ent/media"
|
||||
import (
|
||||
"polaris/ent/media"
|
||||
"polaris/pkg/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
Version = "undefined"
|
||||
Version = "undefined"
|
||||
DefaultTmdbApiKey = ""
|
||||
)
|
||||
|
||||
@@ -37,9 +40,12 @@ const (
|
||||
|
||||
const (
|
||||
IndexerTorznabImpl = "torznab"
|
||||
DataPath = "./data"
|
||||
ImgPath = DataPath + "/img"
|
||||
LogPath = DataPath + "/logs"
|
||||
)
|
||||
|
||||
var (
|
||||
DataPath = utils.GetUserDataDir()
|
||||
ImgPath = DataPath + "/img"
|
||||
LogPath = DataPath + "/logs"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -49,7 +55,7 @@ const (
|
||||
|
||||
const DefaultNamingFormat = "{{.NameCN}} {{.NameEN}} {{if .Year}} ({{.Year}}) {{end}}"
|
||||
|
||||
//https://en.wikipedia.org/wiki/Video_file_format
|
||||
// https://en.wikipedia.org/wiki/Video_file_format
|
||||
var defaultAcceptedVideoFormats = []string{
|
||||
".webm", ".mkv", ".flv", ".vob", ".ogv", ".ogg", ".drc", ".mng", ".avi", ".mts", ".m2ts", ".ts",
|
||||
".mov", ".qt", ".wmv", ".yuv", ".rm", ".rmvb", ".viv", ".amv", ".mp4", ".m4p", ".m4v",
|
||||
|
||||
28
db/db.go
28
db/db.go
@@ -62,7 +62,17 @@ func (c *client) init() {
|
||||
downloadDir := c.GetSetting(SettingDownloadDir)
|
||||
if downloadDir == "" {
|
||||
log.Infof("set default download dir")
|
||||
c.SetSetting(SettingDownloadDir, "/downloads")
|
||||
if utils.IsRunningInDocker() {
|
||||
c.SetSetting(SettingDownloadDir, "/downloads")
|
||||
} else {
|
||||
downloadDir, err := utils.UserDownloadDir()
|
||||
if err != nil {
|
||||
log.Errorf("get user download dir error: %v", err)
|
||||
downloadDir = "/downloads"
|
||||
}
|
||||
c.SetSetting(SettingDownloadDir, downloadDir)
|
||||
}
|
||||
|
||||
}
|
||||
logLevel := c.GetSetting(SettingLogLevel)
|
||||
if logLevel == "" {
|
||||
@@ -329,11 +339,11 @@ func (c *client) SaveDownloader(downloader *ent.DownloadClients) error {
|
||||
count := c.ent.DownloadClients.Query().Where(downloadclients.Name(downloader.Name)).CountX(context.TODO())
|
||||
if count != 0 {
|
||||
err := c.ent.DownloadClients.Update().Where(downloadclients.Name(downloader.Name)).SetImplementation(downloader.Implementation).
|
||||
SetURL(downloader.URL).SetUser(downloader.User).SetPassword(downloader.Password).SetPriority1(downloader.Priority1).Exec(context.TODO())
|
||||
SetURL(downloader.URL).SetUser(downloader.User).SetUseNatTraversal(downloader.UseNatTraversal).SetPassword(downloader.Password).SetPriority1(downloader.Priority1).Exec(context.TODO())
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := c.ent.DownloadClients.Create().SetEnable(true).SetImplementation(downloader.Implementation).
|
||||
_, err := c.ent.DownloadClients.Create().SetEnable(true).SetImplementation(downloader.Implementation).SetUseNatTraversal(downloader.UseNatTraversal).
|
||||
SetName(downloader.Name).SetURL(downloader.URL).SetUser(downloader.User).SetPriority1(downloader.Priority1).SetPassword(downloader.Password).Save(context.TODO())
|
||||
return err
|
||||
}
|
||||
@@ -390,11 +400,13 @@ type WebdavSetting struct {
|
||||
}
|
||||
|
||||
func (c *client) AddStorage(st *StorageInfo) error {
|
||||
if !strings.HasSuffix(st.TvPath, "/") {
|
||||
st.TvPath += "/"
|
||||
}
|
||||
if !strings.HasSuffix(st.MoviePath, "/") {
|
||||
st.MoviePath += "/"
|
||||
if st.Implementation != storage.ImplementationLocal.String() { //add seperator if not local storage
|
||||
if !strings.HasSuffix(st.TvPath, "/") {
|
||||
st.TvPath += "/"
|
||||
}
|
||||
if !strings.HasSuffix(st.MoviePath, "/") {
|
||||
st.MoviePath += "/"
|
||||
}
|
||||
}
|
||||
if st.Settings == nil {
|
||||
st.Settings = map[string]string{}
|
||||
|
||||
9
doc/stun_nat_traversal.md
Normal file
9
doc/stun_nat_traversal.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 利用STUN进行NAT内网穿透
|
||||
|
||||
可以在下载器选项里打开 *使用内置STUN NAT穿透* 功能,即使处在NAT网络环境下,BT/PT也可以满速上传。打开后Polaris自动更改下载客户端的监听端口,并代理BT的上传流量。
|
||||
|
||||
要想正常使用此功能,需要具备以下几个条件:
|
||||
|
||||
1. 所在的NAT网络非对称NAT(Symmetric NAT),可以使用 [NatTypeTester](https://github.com/HMBSbige/NatTypeTester/releases/) 检查自己的网络的NAT类型
|
||||
2. 下载器设置选项中下载器地址为下载器docker的实际地址,而非映射地址。达到这一目标可以使用host网络创建下载器,也可以利用docker-compose自带的域名解析来实现
|
||||
|
||||
46
docker/docker-compose.yml
Normal file
46
docker/docker-compose.yml
Normal file
@@ -0,0 +1,46 @@
|
||||
services:
|
||||
polaris:
|
||||
image: ghcr.io/simon-ding/polaris:latest
|
||||
restart: always
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=${TIMEZONE}
|
||||
volumes:
|
||||
- ${CONFIGURATION_FILE_LOCATION}/polaris:/app/data
|
||||
- ${DOWNLOAD_LOCATION}:/downloads
|
||||
- ${MEDIA_LOCATION}:/data
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 3322:8080
|
||||
transmission:
|
||||
image: lscr.io/linuxserver/transmission:latest
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=${TIMEZONE}
|
||||
volumes:
|
||||
- ${CONFIGURATION_FILE_LOCATION}/transmission:/config
|
||||
- ${DOWNLOAD_LOCATION}:/downloads
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
ports:
|
||||
- 9091:9091
|
||||
- 51413:51413
|
||||
- 51413:51413/udp
|
||||
prowlarr:
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=${TIMEZONE}
|
||||
volumes:
|
||||
- ${CONFIGURATION_FILE_LOCATION}/prowlar:/config
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- 9696:9696
|
||||
restart: always
|
||||
12
docker/example.env
Normal file
12
docker/example.env
Normal file
@@ -0,0 +1,12 @@
|
||||
#下载路径
|
||||
DOWNLOAD_LOCATION=/downloads
|
||||
|
||||
#媒体数据存储路径,也可以启动自己配置webdav存储
|
||||
MEDIA_LOCATION=/data
|
||||
|
||||
#程序配置文件存放路径
|
||||
CONFIGURATION_FILE_LOCATION=./config
|
||||
|
||||
#时区
|
||||
TIMEZONE=Asia/Shanghai
|
||||
|
||||
@@ -140,7 +140,7 @@ func (c *Engine) reloadTasks() {
|
||||
c.tasks.Store(t.ID, &Task{Torrent: to})
|
||||
}
|
||||
} else if dl.Implementation == downloadclients.ImplementationBuildin {
|
||||
err := c.reloadUsingBuildinDownloader(t)
|
||||
err := c.reloadUsingBuildinDownloader(t)
|
||||
if err != nil {
|
||||
log.Warnf("buildin downloader error: %v", err)
|
||||
} else {
|
||||
|
||||
@@ -217,11 +217,18 @@ func (c *Engine) AddTv2Watchlist(in AddWatchlistIn) (interface{}, error) {
|
||||
Limiter: schema.MediaLimiter{SizeMin: in.SizeMin, SizeMax: in.SizeMax},
|
||||
Extras: schema.MediaExtras{
|
||||
OriginalLanguage: detail.OriginalLanguage,
|
||||
Genres: detail.Genres,
|
||||
//Genres: detail.Genres,
|
||||
},
|
||||
AlternativeTitles: alterTitles,
|
||||
}
|
||||
|
||||
for _, g := range detail.Genres {
|
||||
m.Extras.Genres = append(m.Extras.Genres, schema.Genre{
|
||||
ID: g.ID,
|
||||
Name: g.Name,
|
||||
})
|
||||
}
|
||||
|
||||
r, err := c.db.AddMediaWatchlist(m, epIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "add to list")
|
||||
@@ -338,7 +345,14 @@ func (c *Engine) AddMovie2Watchlist(in AddWatchlistIn) (interface{}, error) {
|
||||
extras := schema.MediaExtras{
|
||||
IsAdultMovie: detail.Adult,
|
||||
OriginalLanguage: detail.OriginalLanguage,
|
||||
Genres: detail.Genres,
|
||||
//Genres: detail.Genres,
|
||||
}
|
||||
|
||||
for _, g := range detail.Genres {
|
||||
extras.Genres = append(extras.Genres, schema.Genre{
|
||||
ID: g.ID,
|
||||
Name: g.Name,
|
||||
})
|
||||
}
|
||||
if IsJav(detail) {
|
||||
javid := c.GetJavid(in.TmdbID)
|
||||
|
||||
@@ -40,7 +40,7 @@ func (c *Engine) addSysCron() {
|
||||
return nil
|
||||
})
|
||||
c.registerCronJob("check_series_new_release", "0 0 */12 * * *", c.checkAllSeriesNewSeason)
|
||||
c.registerCronJob("update_import_lists", "0 30 * * * *", c.periodicallyUpdateImportlist)
|
||||
c.registerCronJob("update_import_lists", "0 */20 * * * *", c.periodicallyUpdateImportlist)
|
||||
|
||||
c.schedulers.Range(func(key string, value scheduler) bool {
|
||||
log.Debugf("add cron job: %v", key)
|
||||
|
||||
56
engine/stun.go
Normal file
56
engine/stun.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"polaris/ent/downloadclients"
|
||||
"polaris/log"
|
||||
"polaris/pkg/nat"
|
||||
"polaris/pkg/qbittorrent"
|
||||
|
||||
"github.com/pion/stun/v3"
|
||||
)
|
||||
|
||||
func (s *Engine) stunProxyDownloadClient() error {
|
||||
|
||||
return s.StartStunProxy("")
|
||||
}
|
||||
|
||||
|
||||
func (s *Engine) StartStunProxy(name string) error {
|
||||
downloaders := s.db.GetAllDonloadClients()
|
||||
for _, d := range downloaders {
|
||||
if !d.Enable {
|
||||
continue
|
||||
}
|
||||
if !d.UseNatTraversal {
|
||||
continue
|
||||
}
|
||||
if name != "" && d.Name != name {
|
||||
continue
|
||||
}
|
||||
|
||||
if d.Implementation != downloadclients.ImplementationQbittorrent { //TODO only support qbittorrent for now
|
||||
continue
|
||||
}
|
||||
|
||||
qbt, err := qbittorrent.NewClient(d.URL, d.User, d.Password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect to download client error: %v", d.URL)
|
||||
}
|
||||
u, err := url.Parse(d.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("start stun proxy for %s", d.Name)
|
||||
n, err := nat.NewNatTraversal(func(xa stun.XORMappedAddress) error {
|
||||
return qbt.SetListenPort(xa.Port)
|
||||
}, u.Hostname())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.StartProxy()
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -71,6 +72,26 @@ func names2Query(media *ent.Media) []string {
|
||||
return names
|
||||
}
|
||||
|
||||
func getSeasonReleaseYear(series *db.MediaDetails, seasonNum int) int {
|
||||
if seasonNum == 0 {
|
||||
return 0
|
||||
}
|
||||
releaseYear := 0
|
||||
for _, s := range series.Episodes {
|
||||
if s.SeasonNumber == seasonNum && s.AirDate != "" {
|
||||
ss := strings.Split(s.AirDate, "-")[0]
|
||||
y, err := strconv.Atoi(ss)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
releaseYear = y
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
return releaseYear
|
||||
}
|
||||
|
||||
func SearchTvSeries(db1 db.Database, param *SearchParam) ([]torznab.Result, error) {
|
||||
series, err := db1.GetMediaDetails(param.MediaId)
|
||||
if err != nil {
|
||||
@@ -87,6 +108,11 @@ func SearchTvSeries(db1 db.Database, param *SearchParam) ([]torznab.Result, erro
|
||||
|
||||
res := searchWithTorznab(db1, SearchTypeTv, names...)
|
||||
|
||||
ss := strings.Split(series.AirDate, "-")[0]
|
||||
releaseYear, _ := strconv.Atoi(ss)
|
||||
|
||||
seasonYear := getSeasonReleaseYear(series, param.SeasonNum)
|
||||
|
||||
var filtered []torznab.Result
|
||||
lo:
|
||||
for _, r := range res {
|
||||
@@ -102,6 +128,17 @@ lo:
|
||||
if !torrentNameOk(series, meta) {
|
||||
continue
|
||||
}
|
||||
if meta.Year > 0 && releaseYear > 0 {
|
||||
if meta.Year != releaseYear && meta.Year != releaseYear-1 && meta.Year != releaseYear+1 { //year not match
|
||||
if seasonYear > 0 { // if tv release year is not match, check season release year
|
||||
if meta.Year != seasonYear && meta.Year != seasonYear-1 && meta.Year != seasonYear+1 { //season year not match
|
||||
continue lo
|
||||
}
|
||||
} else {
|
||||
continue lo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !isNoSeasonSeries(series) && meta.Season != param.SeasonNum { //do not check season on series that only rely on episode number
|
||||
@@ -311,6 +348,10 @@ const (
|
||||
)
|
||||
|
||||
func searchWithTorznab(db db.Database, t SearchType, queries ...string) []torznab.Result {
|
||||
t1 := time.Now()
|
||||
defer func() {
|
||||
log.Infof("search with torznab took %v", time.Since(t1))
|
||||
}()
|
||||
|
||||
var res []torznab.Result
|
||||
allTorznab := db.GetAllIndexers()
|
||||
|
||||
@@ -33,6 +33,8 @@ type DownloadClients struct {
|
||||
Settings string `json:"settings,omitempty"`
|
||||
// Priority1 holds the value of the "priority1" field.
|
||||
Priority1 int `json:"priority1,omitempty"`
|
||||
// use stun server to do nat traversal, enable download client to do uploading successfully
|
||||
UseNatTraversal bool `json:"use_nat_traversal,omitempty"`
|
||||
// RemoveCompletedDownloads holds the value of the "remove_completed_downloads" field.
|
||||
RemoveCompletedDownloads bool `json:"remove_completed_downloads,omitempty"`
|
||||
// RemoveFailedDownloads holds the value of the "remove_failed_downloads" field.
|
||||
@@ -49,7 +51,7 @@ func (*DownloadClients) scanValues(columns []string) ([]any, error) {
|
||||
values := make([]any, len(columns))
|
||||
for i := range columns {
|
||||
switch columns[i] {
|
||||
case downloadclients.FieldEnable, downloadclients.FieldRemoveCompletedDownloads, downloadclients.FieldRemoveFailedDownloads:
|
||||
case downloadclients.FieldEnable, downloadclients.FieldUseNatTraversal, downloadclients.FieldRemoveCompletedDownloads, downloadclients.FieldRemoveFailedDownloads:
|
||||
values[i] = new(sql.NullBool)
|
||||
case downloadclients.FieldID, downloadclients.FieldPriority1:
|
||||
values[i] = new(sql.NullInt64)
|
||||
@@ -126,6 +128,12 @@ func (dc *DownloadClients) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
dc.Priority1 = int(value.Int64)
|
||||
}
|
||||
case downloadclients.FieldUseNatTraversal:
|
||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field use_nat_traversal", values[i])
|
||||
} else if value.Valid {
|
||||
dc.UseNatTraversal = value.Bool
|
||||
}
|
||||
case downloadclients.FieldRemoveCompletedDownloads:
|
||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field remove_completed_downloads", values[i])
|
||||
@@ -210,6 +218,9 @@ func (dc *DownloadClients) String() string {
|
||||
builder.WriteString("priority1=")
|
||||
builder.WriteString(fmt.Sprintf("%v", dc.Priority1))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("use_nat_traversal=")
|
||||
builder.WriteString(fmt.Sprintf("%v", dc.UseNatTraversal))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("remove_completed_downloads=")
|
||||
builder.WriteString(fmt.Sprintf("%v", dc.RemoveCompletedDownloads))
|
||||
builder.WriteString(", ")
|
||||
|
||||
@@ -30,6 +30,8 @@ const (
|
||||
FieldSettings = "settings"
|
||||
// FieldPriority1 holds the string denoting the priority1 field in the database.
|
||||
FieldPriority1 = "priority1"
|
||||
// FieldUseNatTraversal holds the string denoting the use_nat_traversal field in the database.
|
||||
FieldUseNatTraversal = "use_nat_traversal"
|
||||
// FieldRemoveCompletedDownloads holds the string denoting the remove_completed_downloads field in the database.
|
||||
FieldRemoveCompletedDownloads = "remove_completed_downloads"
|
||||
// FieldRemoveFailedDownloads holds the string denoting the remove_failed_downloads field in the database.
|
||||
@@ -53,6 +55,7 @@ var Columns = []string{
|
||||
FieldPassword,
|
||||
FieldSettings,
|
||||
FieldPriority1,
|
||||
FieldUseNatTraversal,
|
||||
FieldRemoveCompletedDownloads,
|
||||
FieldRemoveFailedDownloads,
|
||||
FieldTags,
|
||||
@@ -80,6 +83,8 @@ var (
|
||||
DefaultPriority1 int
|
||||
// Priority1Validator is a validator for the "priority1" field. It is called by the builders before save.
|
||||
Priority1Validator func(int) error
|
||||
// DefaultUseNatTraversal holds the default value on creation for the "use_nat_traversal" field.
|
||||
DefaultUseNatTraversal bool
|
||||
// DefaultRemoveCompletedDownloads holds the default value on creation for the "remove_completed_downloads" field.
|
||||
DefaultRemoveCompletedDownloads bool
|
||||
// DefaultRemoveFailedDownloads holds the default value on creation for the "remove_failed_downloads" field.
|
||||
@@ -162,6 +167,11 @@ func ByPriority1(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPriority1, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByUseNatTraversal orders the results by the use_nat_traversal field.
|
||||
func ByUseNatTraversal(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldUseNatTraversal, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByRemoveCompletedDownloads orders the results by the remove_completed_downloads field.
|
||||
func ByRemoveCompletedDownloads(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldRemoveCompletedDownloads, opts...).ToFunc()
|
||||
|
||||
@@ -89,6 +89,11 @@ func Priority1(v int) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldEQ(FieldPriority1, v))
|
||||
}
|
||||
|
||||
// UseNatTraversal applies equality check predicate on the "use_nat_traversal" field. It's identical to UseNatTraversalEQ.
|
||||
func UseNatTraversal(v bool) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldEQ(FieldUseNatTraversal, v))
|
||||
}
|
||||
|
||||
// RemoveCompletedDownloads applies equality check predicate on the "remove_completed_downloads" field. It's identical to RemoveCompletedDownloadsEQ.
|
||||
func RemoveCompletedDownloads(v bool) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldEQ(FieldRemoveCompletedDownloads, v))
|
||||
@@ -504,6 +509,26 @@ func Priority1LTE(v int) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldLTE(FieldPriority1, v))
|
||||
}
|
||||
|
||||
// UseNatTraversalEQ applies the EQ predicate on the "use_nat_traversal" field.
|
||||
func UseNatTraversalEQ(v bool) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldEQ(FieldUseNatTraversal, v))
|
||||
}
|
||||
|
||||
// UseNatTraversalNEQ applies the NEQ predicate on the "use_nat_traversal" field.
|
||||
func UseNatTraversalNEQ(v bool) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldNEQ(FieldUseNatTraversal, v))
|
||||
}
|
||||
|
||||
// UseNatTraversalIsNil applies the IsNil predicate on the "use_nat_traversal" field.
|
||||
func UseNatTraversalIsNil() predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldIsNull(FieldUseNatTraversal))
|
||||
}
|
||||
|
||||
// UseNatTraversalNotNil applies the NotNil predicate on the "use_nat_traversal" field.
|
||||
func UseNatTraversalNotNil() predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldNotNull(FieldUseNatTraversal))
|
||||
}
|
||||
|
||||
// RemoveCompletedDownloadsEQ applies the EQ predicate on the "remove_completed_downloads" field.
|
||||
func RemoveCompletedDownloadsEQ(v bool) predicate.DownloadClients {
|
||||
return predicate.DownloadClients(sql.FieldEQ(FieldRemoveCompletedDownloads, v))
|
||||
|
||||
@@ -100,6 +100,20 @@ func (dcc *DownloadClientsCreate) SetNillablePriority1(i *int) *DownloadClientsC
|
||||
return dcc
|
||||
}
|
||||
|
||||
// SetUseNatTraversal sets the "use_nat_traversal" field.
|
||||
func (dcc *DownloadClientsCreate) SetUseNatTraversal(b bool) *DownloadClientsCreate {
|
||||
dcc.mutation.SetUseNatTraversal(b)
|
||||
return dcc
|
||||
}
|
||||
|
||||
// SetNillableUseNatTraversal sets the "use_nat_traversal" field if the given value is not nil.
|
||||
func (dcc *DownloadClientsCreate) SetNillableUseNatTraversal(b *bool) *DownloadClientsCreate {
|
||||
if b != nil {
|
||||
dcc.SetUseNatTraversal(*b)
|
||||
}
|
||||
return dcc
|
||||
}
|
||||
|
||||
// SetRemoveCompletedDownloads sets the "remove_completed_downloads" field.
|
||||
func (dcc *DownloadClientsCreate) SetRemoveCompletedDownloads(b bool) *DownloadClientsCreate {
|
||||
dcc.mutation.SetRemoveCompletedDownloads(b)
|
||||
@@ -207,6 +221,10 @@ func (dcc *DownloadClientsCreate) defaults() {
|
||||
v := downloadclients.DefaultPriority1
|
||||
dcc.mutation.SetPriority1(v)
|
||||
}
|
||||
if _, ok := dcc.mutation.UseNatTraversal(); !ok {
|
||||
v := downloadclients.DefaultUseNatTraversal
|
||||
dcc.mutation.SetUseNatTraversal(v)
|
||||
}
|
||||
if _, ok := dcc.mutation.RemoveCompletedDownloads(); !ok {
|
||||
v := downloadclients.DefaultRemoveCompletedDownloads
|
||||
dcc.mutation.SetRemoveCompletedDownloads(v)
|
||||
@@ -328,6 +346,10 @@ func (dcc *DownloadClientsCreate) createSpec() (*DownloadClients, *sqlgraph.Crea
|
||||
_spec.SetField(downloadclients.FieldPriority1, field.TypeInt, value)
|
||||
_node.Priority1 = value
|
||||
}
|
||||
if value, ok := dcc.mutation.UseNatTraversal(); ok {
|
||||
_spec.SetField(downloadclients.FieldUseNatTraversal, field.TypeBool, value)
|
||||
_node.UseNatTraversal = value
|
||||
}
|
||||
if value, ok := dcc.mutation.RemoveCompletedDownloads(); ok {
|
||||
_spec.SetField(downloadclients.FieldRemoveCompletedDownloads, field.TypeBool, value)
|
||||
_node.RemoveCompletedDownloads = value
|
||||
|
||||
@@ -146,6 +146,26 @@ func (dcu *DownloadClientsUpdate) AddPriority1(i int) *DownloadClientsUpdate {
|
||||
return dcu
|
||||
}
|
||||
|
||||
// SetUseNatTraversal sets the "use_nat_traversal" field.
|
||||
func (dcu *DownloadClientsUpdate) SetUseNatTraversal(b bool) *DownloadClientsUpdate {
|
||||
dcu.mutation.SetUseNatTraversal(b)
|
||||
return dcu
|
||||
}
|
||||
|
||||
// SetNillableUseNatTraversal sets the "use_nat_traversal" field if the given value is not nil.
|
||||
func (dcu *DownloadClientsUpdate) SetNillableUseNatTraversal(b *bool) *DownloadClientsUpdate {
|
||||
if b != nil {
|
||||
dcu.SetUseNatTraversal(*b)
|
||||
}
|
||||
return dcu
|
||||
}
|
||||
|
||||
// ClearUseNatTraversal clears the value of the "use_nat_traversal" field.
|
||||
func (dcu *DownloadClientsUpdate) ClearUseNatTraversal() *DownloadClientsUpdate {
|
||||
dcu.mutation.ClearUseNatTraversal()
|
||||
return dcu
|
||||
}
|
||||
|
||||
// SetRemoveCompletedDownloads sets the "remove_completed_downloads" field.
|
||||
func (dcu *DownloadClientsUpdate) SetRemoveCompletedDownloads(b bool) *DownloadClientsUpdate {
|
||||
dcu.mutation.SetRemoveCompletedDownloads(b)
|
||||
@@ -274,6 +294,12 @@ func (dcu *DownloadClientsUpdate) sqlSave(ctx context.Context) (n int, err error
|
||||
if value, ok := dcu.mutation.AddedPriority1(); ok {
|
||||
_spec.AddField(downloadclients.FieldPriority1, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := dcu.mutation.UseNatTraversal(); ok {
|
||||
_spec.SetField(downloadclients.FieldUseNatTraversal, field.TypeBool, value)
|
||||
}
|
||||
if dcu.mutation.UseNatTraversalCleared() {
|
||||
_spec.ClearField(downloadclients.FieldUseNatTraversal, field.TypeBool)
|
||||
}
|
||||
if value, ok := dcu.mutation.RemoveCompletedDownloads(); ok {
|
||||
_spec.SetField(downloadclients.FieldRemoveCompletedDownloads, field.TypeBool, value)
|
||||
}
|
||||
@@ -425,6 +451,26 @@ func (dcuo *DownloadClientsUpdateOne) AddPriority1(i int) *DownloadClientsUpdate
|
||||
return dcuo
|
||||
}
|
||||
|
||||
// SetUseNatTraversal sets the "use_nat_traversal" field.
|
||||
func (dcuo *DownloadClientsUpdateOne) SetUseNatTraversal(b bool) *DownloadClientsUpdateOne {
|
||||
dcuo.mutation.SetUseNatTraversal(b)
|
||||
return dcuo
|
||||
}
|
||||
|
||||
// SetNillableUseNatTraversal sets the "use_nat_traversal" field if the given value is not nil.
|
||||
func (dcuo *DownloadClientsUpdateOne) SetNillableUseNatTraversal(b *bool) *DownloadClientsUpdateOne {
|
||||
if b != nil {
|
||||
dcuo.SetUseNatTraversal(*b)
|
||||
}
|
||||
return dcuo
|
||||
}
|
||||
|
||||
// ClearUseNatTraversal clears the value of the "use_nat_traversal" field.
|
||||
func (dcuo *DownloadClientsUpdateOne) ClearUseNatTraversal() *DownloadClientsUpdateOne {
|
||||
dcuo.mutation.ClearUseNatTraversal()
|
||||
return dcuo
|
||||
}
|
||||
|
||||
// SetRemoveCompletedDownloads sets the "remove_completed_downloads" field.
|
||||
func (dcuo *DownloadClientsUpdateOne) SetRemoveCompletedDownloads(b bool) *DownloadClientsUpdateOne {
|
||||
dcuo.mutation.SetRemoveCompletedDownloads(b)
|
||||
@@ -583,6 +629,12 @@ func (dcuo *DownloadClientsUpdateOne) sqlSave(ctx context.Context) (_node *Downl
|
||||
if value, ok := dcuo.mutation.AddedPriority1(); ok {
|
||||
_spec.AddField(downloadclients.FieldPriority1, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := dcuo.mutation.UseNatTraversal(); ok {
|
||||
_spec.SetField(downloadclients.FieldUseNatTraversal, field.TypeBool, value)
|
||||
}
|
||||
if dcuo.mutation.UseNatTraversalCleared() {
|
||||
_spec.ClearField(downloadclients.FieldUseNatTraversal, field.TypeBool)
|
||||
}
|
||||
if value, ok := dcuo.mutation.RemoveCompletedDownloads(); ok {
|
||||
_spec.SetField(downloadclients.FieldRemoveCompletedDownloads, field.TypeBool, value)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ var (
|
||||
{Name: "password", Type: field.TypeString, Default: ""},
|
||||
{Name: "settings", Type: field.TypeString, Default: ""},
|
||||
{Name: "priority1", Type: field.TypeInt, Default: 1},
|
||||
{Name: "use_nat_traversal", Type: field.TypeBool, Nullable: true, Default: false},
|
||||
{Name: "remove_completed_downloads", Type: field.TypeBool, Default: true},
|
||||
{Name: "remove_failed_downloads", Type: field.TypeBool, Default: true},
|
||||
{Name: "tags", Type: field.TypeString, Default: ""},
|
||||
|
||||
@@ -792,6 +792,7 @@ type DownloadClientsMutation struct {
|
||||
settings *string
|
||||
priority1 *int
|
||||
addpriority1 *int
|
||||
use_nat_traversal *bool
|
||||
remove_completed_downloads *bool
|
||||
remove_failed_downloads *bool
|
||||
tags *string
|
||||
@@ -1208,6 +1209,55 @@ func (m *DownloadClientsMutation) ResetPriority1() {
|
||||
m.addpriority1 = nil
|
||||
}
|
||||
|
||||
// SetUseNatTraversal sets the "use_nat_traversal" field.
|
||||
func (m *DownloadClientsMutation) SetUseNatTraversal(b bool) {
|
||||
m.use_nat_traversal = &b
|
||||
}
|
||||
|
||||
// UseNatTraversal returns the value of the "use_nat_traversal" field in the mutation.
|
||||
func (m *DownloadClientsMutation) UseNatTraversal() (r bool, exists bool) {
|
||||
v := m.use_nat_traversal
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldUseNatTraversal returns the old "use_nat_traversal" field's value of the DownloadClients entity.
|
||||
// If the DownloadClients object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *DownloadClientsMutation) OldUseNatTraversal(ctx context.Context) (v bool, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldUseNatTraversal is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldUseNatTraversal requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldUseNatTraversal: %w", err)
|
||||
}
|
||||
return oldValue.UseNatTraversal, nil
|
||||
}
|
||||
|
||||
// ClearUseNatTraversal clears the value of the "use_nat_traversal" field.
|
||||
func (m *DownloadClientsMutation) ClearUseNatTraversal() {
|
||||
m.use_nat_traversal = nil
|
||||
m.clearedFields[downloadclients.FieldUseNatTraversal] = struct{}{}
|
||||
}
|
||||
|
||||
// UseNatTraversalCleared returns if the "use_nat_traversal" field was cleared in this mutation.
|
||||
func (m *DownloadClientsMutation) UseNatTraversalCleared() bool {
|
||||
_, ok := m.clearedFields[downloadclients.FieldUseNatTraversal]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetUseNatTraversal resets all changes to the "use_nat_traversal" field.
|
||||
func (m *DownloadClientsMutation) ResetUseNatTraversal() {
|
||||
m.use_nat_traversal = nil
|
||||
delete(m.clearedFields, downloadclients.FieldUseNatTraversal)
|
||||
}
|
||||
|
||||
// SetRemoveCompletedDownloads sets the "remove_completed_downloads" field.
|
||||
func (m *DownloadClientsMutation) SetRemoveCompletedDownloads(b bool) {
|
||||
m.remove_completed_downloads = &b
|
||||
@@ -1399,7 +1449,7 @@ func (m *DownloadClientsMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *DownloadClientsMutation) Fields() []string {
|
||||
fields := make([]string, 0, 12)
|
||||
fields := make([]string, 0, 13)
|
||||
if m.enable != nil {
|
||||
fields = append(fields, downloadclients.FieldEnable)
|
||||
}
|
||||
@@ -1424,6 +1474,9 @@ func (m *DownloadClientsMutation) Fields() []string {
|
||||
if m.priority1 != nil {
|
||||
fields = append(fields, downloadclients.FieldPriority1)
|
||||
}
|
||||
if m.use_nat_traversal != nil {
|
||||
fields = append(fields, downloadclients.FieldUseNatTraversal)
|
||||
}
|
||||
if m.remove_completed_downloads != nil {
|
||||
fields = append(fields, downloadclients.FieldRemoveCompletedDownloads)
|
||||
}
|
||||
@@ -1460,6 +1513,8 @@ func (m *DownloadClientsMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.Settings()
|
||||
case downloadclients.FieldPriority1:
|
||||
return m.Priority1()
|
||||
case downloadclients.FieldUseNatTraversal:
|
||||
return m.UseNatTraversal()
|
||||
case downloadclients.FieldRemoveCompletedDownloads:
|
||||
return m.RemoveCompletedDownloads()
|
||||
case downloadclients.FieldRemoveFailedDownloads:
|
||||
@@ -1493,6 +1548,8 @@ func (m *DownloadClientsMutation) OldField(ctx context.Context, name string) (en
|
||||
return m.OldSettings(ctx)
|
||||
case downloadclients.FieldPriority1:
|
||||
return m.OldPriority1(ctx)
|
||||
case downloadclients.FieldUseNatTraversal:
|
||||
return m.OldUseNatTraversal(ctx)
|
||||
case downloadclients.FieldRemoveCompletedDownloads:
|
||||
return m.OldRemoveCompletedDownloads(ctx)
|
||||
case downloadclients.FieldRemoveFailedDownloads:
|
||||
@@ -1566,6 +1623,13 @@ func (m *DownloadClientsMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetPriority1(v)
|
||||
return nil
|
||||
case downloadclients.FieldUseNatTraversal:
|
||||
v, ok := value.(bool)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetUseNatTraversal(v)
|
||||
return nil
|
||||
case downloadclients.FieldRemoveCompletedDownloads:
|
||||
v, ok := value.(bool)
|
||||
if !ok {
|
||||
@@ -1639,6 +1703,9 @@ func (m *DownloadClientsMutation) AddField(name string, value ent.Value) error {
|
||||
// mutation.
|
||||
func (m *DownloadClientsMutation) ClearedFields() []string {
|
||||
var fields []string
|
||||
if m.FieldCleared(downloadclients.FieldUseNatTraversal) {
|
||||
fields = append(fields, downloadclients.FieldUseNatTraversal)
|
||||
}
|
||||
if m.FieldCleared(downloadclients.FieldCreateTime) {
|
||||
fields = append(fields, downloadclients.FieldCreateTime)
|
||||
}
|
||||
@@ -1656,6 +1723,9 @@ func (m *DownloadClientsMutation) FieldCleared(name string) bool {
|
||||
// error if the field is not defined in the schema.
|
||||
func (m *DownloadClientsMutation) ClearField(name string) error {
|
||||
switch name {
|
||||
case downloadclients.FieldUseNatTraversal:
|
||||
m.ClearUseNatTraversal()
|
||||
return nil
|
||||
case downloadclients.FieldCreateTime:
|
||||
m.ClearCreateTime()
|
||||
return nil
|
||||
@@ -1691,6 +1761,9 @@ func (m *DownloadClientsMutation) ResetField(name string) error {
|
||||
case downloadclients.FieldPriority1:
|
||||
m.ResetPriority1()
|
||||
return nil
|
||||
case downloadclients.FieldUseNatTraversal:
|
||||
m.ResetUseNatTraversal()
|
||||
return nil
|
||||
case downloadclients.FieldRemoveCompletedDownloads:
|
||||
m.ResetRemoveCompletedDownloads()
|
||||
return nil
|
||||
|
||||
@@ -45,20 +45,24 @@ func init() {
|
||||
downloadclients.DefaultPriority1 = downloadclientsDescPriority1.Default.(int)
|
||||
// downloadclients.Priority1Validator is a validator for the "priority1" field. It is called by the builders before save.
|
||||
downloadclients.Priority1Validator = downloadclientsDescPriority1.Validators[0].(func(int) error)
|
||||
// downloadclientsDescUseNatTraversal is the schema descriptor for use_nat_traversal field.
|
||||
downloadclientsDescUseNatTraversal := downloadclientsFields[8].Descriptor()
|
||||
// downloadclients.DefaultUseNatTraversal holds the default value on creation for the use_nat_traversal field.
|
||||
downloadclients.DefaultUseNatTraversal = downloadclientsDescUseNatTraversal.Default.(bool)
|
||||
// downloadclientsDescRemoveCompletedDownloads is the schema descriptor for remove_completed_downloads field.
|
||||
downloadclientsDescRemoveCompletedDownloads := downloadclientsFields[8].Descriptor()
|
||||
downloadclientsDescRemoveCompletedDownloads := downloadclientsFields[9].Descriptor()
|
||||
// downloadclients.DefaultRemoveCompletedDownloads holds the default value on creation for the remove_completed_downloads field.
|
||||
downloadclients.DefaultRemoveCompletedDownloads = downloadclientsDescRemoveCompletedDownloads.Default.(bool)
|
||||
// downloadclientsDescRemoveFailedDownloads is the schema descriptor for remove_failed_downloads field.
|
||||
downloadclientsDescRemoveFailedDownloads := downloadclientsFields[9].Descriptor()
|
||||
downloadclientsDescRemoveFailedDownloads := downloadclientsFields[10].Descriptor()
|
||||
// downloadclients.DefaultRemoveFailedDownloads holds the default value on creation for the remove_failed_downloads field.
|
||||
downloadclients.DefaultRemoveFailedDownloads = downloadclientsDescRemoveFailedDownloads.Default.(bool)
|
||||
// downloadclientsDescTags is the schema descriptor for tags field.
|
||||
downloadclientsDescTags := downloadclientsFields[10].Descriptor()
|
||||
downloadclientsDescTags := downloadclientsFields[11].Descriptor()
|
||||
// downloadclients.DefaultTags holds the default value on creation for the tags field.
|
||||
downloadclients.DefaultTags = downloadclientsDescTags.Default.(string)
|
||||
// downloadclientsDescCreateTime is the schema descriptor for create_time field.
|
||||
downloadclientsDescCreateTime := downloadclientsFields[11].Descriptor()
|
||||
downloadclientsDescCreateTime := downloadclientsFields[12].Descriptor()
|
||||
// downloadclients.DefaultCreateTime holds the default value on creation for the create_time field.
|
||||
downloadclients.DefaultCreateTime = downloadclientsDescCreateTime.Default.(func() time.Time)
|
||||
episodeFields := schema.Episode{}.Fields()
|
||||
|
||||
@@ -32,6 +32,7 @@ func (DownloadClients) Fields() []ent.Field {
|
||||
}
|
||||
return nil
|
||||
}),
|
||||
field.Bool("use_nat_traversal").Optional().Default(false).Comment("use stun server to do nat traversal, enable download client to do uploading successfully"),
|
||||
field.Bool("remove_completed_downloads").Default(true),
|
||||
field.Bool("remove_failed_downloads").Default(true),
|
||||
field.String("tags").Default(""),
|
||||
|
||||
@@ -60,10 +60,12 @@ type MediaExtras struct {
|
||||
JavId string `json:"javid"`
|
||||
//OriginCountry []string `json:"origin_country"`
|
||||
OriginalLanguage string `json:"original_language"`
|
||||
Genres []struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
} `json:"genres"`
|
||||
Genres []Genre `json:"genres"`
|
||||
}
|
||||
|
||||
type Genre struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (m *MediaExtras) IsJav() bool {
|
||||
|
||||
@@ -9,4 +9,4 @@ chown -R "${PUID}:${PGID}" /app/data
|
||||
umask ${UMASK:-022}
|
||||
|
||||
cd /app
|
||||
exec gosu "${PUID}:${PGID}" /app/polaris
|
||||
exec gosu "${PUID}:${PGID}" /app/polaris -port ${PORT:-8080}
|
||||
111
go.mod
111
go.mod
@@ -1,28 +1,30 @@
|
||||
module polaris
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
entgo.io/ent v0.13.1
|
||||
entgo.io/ent v0.14.4
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||
github.com/robfig/cron v1.2.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/net v0.39.0
|
||||
golang.org/x/net v0.42.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PuerkitoBio/goquery v1.10.1
|
||||
github.com/anacrolix/torrent v1.58.1
|
||||
github.com/PuerkitoBio/goquery v1.10.3
|
||||
github.com/anacrolix/torrent v1.59.1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
|
||||
github.com/gin-contrib/zap v1.1.3
|
||||
github.com/gocolly/colly v1.2.0
|
||||
github.com/ncruces/go-sqlite3 v0.18.4
|
||||
github.com/nikoksr/notify v1.0.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golift.io/starr v1.0.0
|
||||
github.com/ncruces/go-sqlite3 v0.28.0
|
||||
github.com/nikoksr/notify v1.3.0
|
||||
github.com/openai/openai-go v1.12.0
|
||||
github.com/pion/stun/v3 v3.0.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golift.io/starr v1.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -31,39 +33,42 @@ require (
|
||||
github.com/RoaringBitmap/roaring v1.2.3 // indirect
|
||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
|
||||
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
||||
github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8 // indirect
|
||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 // indirect
|
||||
github.com/anacrolix/chansync v0.7.0 // indirect
|
||||
github.com/anacrolix/dht/v2 v2.23.0 // indirect
|
||||
github.com/anacrolix/envpprof v1.3.0 // indirect
|
||||
github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca // indirect
|
||||
github.com/anacrolix/generics v0.1.0 // indirect
|
||||
github.com/anacrolix/go-libutp v1.3.2 // indirect
|
||||
github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83 // indirect
|
||||
github.com/anacrolix/log v0.17.0 // indirect
|
||||
github.com/anacrolix/missinggo v1.3.0 // indirect
|
||||
github.com/anacrolix/missinggo/perf v1.0.0 // indirect
|
||||
github.com/anacrolix/missinggo/v2 v2.7.4 // indirect
|
||||
github.com/anacrolix/missinggo/v2 v2.10.0 // indirect
|
||||
github.com/anacrolix/mmsg v1.0.1 // indirect
|
||||
github.com/anacrolix/multiless v0.4.0 // indirect
|
||||
github.com/anacrolix/stm v0.4.0 // indirect
|
||||
github.com/anacrolix/sync v0.5.1 // indirect
|
||||
github.com/anacrolix/stm v0.5.0 // indirect
|
||||
github.com/anacrolix/sync v0.5.4 // indirect
|
||||
github.com/anacrolix/upnp v0.1.4 // indirect
|
||||
github.com/anacrolix/utp v0.1.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/antchfx/htmlquery v1.3.4 // indirect
|
||||
github.com/antchfx/xmlquery v1.4.4 // indirect
|
||||
github.com/antchfx/xpath v1.3.3 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/benbjohnson/immutable v0.3.0 // indirect
|
||||
github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.2 // indirect
|
||||
github.com/blinkbean/dingtalk v1.1.3 // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||
github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 // indirect
|
||||
github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568 // indirect
|
||||
github.com/go-llsqlite/crawshaw v0.5.6-0.20250312230104-194977a03421 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/go-test/deep v1.0.4 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
@@ -81,16 +86,15 @@ require (
|
||||
github.com/pion/datachannel v1.5.9 // indirect
|
||||
github.com/pion/dtls/v3 v3.0.3 // indirect
|
||||
github.com/pion/ice/v4 v4.0.2 // indirect
|
||||
github.com/pion/interceptor v0.1.37 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/interceptor v0.1.40 // indirect
|
||||
github.com/pion/logging v0.2.3 // indirect
|
||||
github.com/pion/mdns/v2 v2.0.7 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.14 // indirect
|
||||
github.com/pion/rtp v1.8.9 // indirect
|
||||
github.com/pion/rtcp v1.2.15 // indirect
|
||||
github.com/pion/rtp v1.8.18 // indirect
|
||||
github.com/pion/sctp v1.8.33 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.9 // indirect
|
||||
github.com/pion/srtp/v3 v3.0.4 // indirect
|
||||
github.com/pion/stun/v3 v3.0.0 // indirect
|
||||
github.com/pion/transport/v3 v3.0.7 // indirect
|
||||
github.com/pion/turn/v4 v4.0.0 // indirect
|
||||
github.com/pion/webrtc/v4 v4.0.0 // indirect
|
||||
@@ -103,16 +107,20 @@ require (
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/temoto/robotstxt v1.1.2 // indirect
|
||||
github.com/tetratelabs/wazero v1.8.0 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/tidwall/btree v1.6.0 // indirect
|
||||
github.com/wlynxg/anet v0.0.3 // indirect
|
||||
github.com/tidwall/gjson v1.18.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.32.0 // indirect
|
||||
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/time v0.8.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -125,66 +133,61 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 // indirect
|
||||
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 // indirect
|
||||
github.com/agext/levenshtein v1.2.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.4
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-contrib/static v1.1.2
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-json v0.10.5
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.13.0 // indirect
|
||||
github.com/hekmon/cunits/v2 v2.1.0 // indirect
|
||||
// indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/zclconf/go-cty v1.8.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.37.0
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/sys v0.32.0
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e
|
||||
golang.org/x/mod v0.26.0 // indirect
|
||||
golang.org/x/sys v0.35.0
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cyruzin/golang-tmdb v1.6.3
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/cyruzin/golang-tmdb v1.8.1
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/hekmon/transmissionrpc/v3 v3.0.0
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/spf13/viper v1.20.1
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
)
|
||||
|
||||
219
go.sum
219
go.sum
@@ -1,13 +1,13 @@
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43 h1:GwdJbXydHCYPedeeLt4x/lrlIISQ4JTH1mRWuE5ZZ14=
|
||||
ariga.io/atlas v0.19.1-0.20240203083654-5948b60a8e43/go.mod h1:uj3pm+hUTVN/X5yfdBexHlZv+1Xu5u5ZbZx7+CDavNU=
|
||||
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 h1:nX4HXncwIdvQ8/8sIUIf1nyCkK8qdBaHQ7EtzPpuiGE=
|
||||
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
||||
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
||||
entgo.io/ent v0.13.1 h1:uD8QwN1h6SNphdCCzmkMN3feSUzNnVvV/WIkHKMbzOE=
|
||||
entgo.io/ent v0.13.1/go.mod h1:qCEmo+biw3ccBn9OyL4ZK5dfpwg++l1Gxwac5B1206A=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
||||
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
entgo.io/ent v0.14.4 h1:/DhDraSLXIkBhyiVoJeSshr4ZYi7femzhj6/TckzZuI=
|
||||
entgo.io/ent v0.14.4/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
@@ -15,8 +15,8 @@ github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7Oputl
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/goquery v1.10.1 h1:Y8JGYUkXWTGRB6Ars3+j3kN0xg1YqqlwvdTV8WTFQcU=
|
||||
github.com/PuerkitoBio/goquery v1.10.1/go.mod h1:IYiHrOMps66ag56LEH7QYDDupKXyo5A8qrjIx3ZtujY=
|
||||
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||
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.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||
@@ -40,8 +40,12 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8 h1:eyb0bBaQKMOh5Se/Qg54shijc8K4zpQiOjEhKFADkQM=
|
||||
github.com/anacrolix/chansync v0.4.1-0.20240627045151-1aa1ac392fe8/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
||||
github.com/anacrolix/chansync v0.7.0 h1:wgwxbsJRmOqNjil4INpxHrDp4rlqQhECxR8/WBP4Et0=
|
||||
github.com/anacrolix/chansync v0.7.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 h1:8V0K09lrGoeT2KRJNOtspA7q+OMxGwQqK/Ug0IiaaRE=
|
||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444/go.mod h1:MctKM1HS5YYDb3F30NGJxLE+QPuqWoT5ReW/4jt8xew=
|
||||
github.com/anacrolix/dht/v2 v2.23.0 h1:EuD17ykTTEkAMPLjBsS5QjGOwuBgLTdQhds6zPAjeVY=
|
||||
github.com/anacrolix/dht/v2 v2.23.0/go.mod h1:seXRz6HLw8zEnxlysf9ye2eQbrKUmch6PyOHpe/Nb/U=
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||
github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
||||
@@ -50,6 +54,8 @@ github.com/anacrolix/envpprof v1.3.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcer
|
||||
github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
||||
github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca h1:aiiGqSQWjtVNdi8zUMfA//IrM8fPkv2bWwZVPbDe0wg=
|
||||
github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8=
|
||||
github.com/anacrolix/generics v0.1.0 h1:r6OgogjCdml3K5A8ixUG0X9DM4jrQiMfIkZiBOGvIfg=
|
||||
github.com/anacrolix/generics v0.1.0/go.mod h1:MN3ve08Z3zSV/rTuX/ouI4lNdlfTxgdafQJiLzyNRB8=
|
||||
github.com/anacrolix/go-libutp v1.3.2 h1:WswiaxTIogchbkzNgGHuHRfbrYLpv4o290mlvcx+++M=
|
||||
github.com/anacrolix/go-libutp v1.3.2/go.mod h1:fCUiEnXJSe3jsPG554A200Qv+45ZzIIyGEvE56SHmyA=
|
||||
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||
@@ -58,8 +64,11 @@ github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+
|
||||
github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
||||
github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83 h1:9o/yVzzLzYaBDFx8B27yhkvBLhNnRAuSTK7Y+yZKVtU=
|
||||
github.com/anacrolix/log v0.15.3-0.20240627045001-cd912c641d83/go.mod h1:xvHjsYWWP7yO8PZwtuIp/k0DBlu07pSJqH4SEC78Vwc=
|
||||
github.com/anacrolix/log v0.17.0 h1:cZvEGRPCbIg+WK+qAxWj/ap2Gj8cx1haOCSVxNZQpK4=
|
||||
github.com/anacrolix/log v0.17.0/go.mod h1:m0poRtlr41mriZlXBQ9SOVZ8yZBkLjOkDhd5Li5pITA=
|
||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM=
|
||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
|
||||
github.com/anacrolix/lsan v0.1.0 h1:TbgB8fdVXgBwrNsJGHtht9+9FepNFu5H7dU8ek6XYAY=
|
||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
||||
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=
|
||||
@@ -72,6 +81,8 @@ github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbU
|
||||
github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA=
|
||||
github.com/anacrolix/missinggo/v2 v2.7.4 h1:47h5OXoPV8JbA/ACA+FLwKdYbAinuDO8osc2Cu9xkxg=
|
||||
github.com/anacrolix/missinggo/v2 v2.7.4/go.mod h1:vVO5FEziQm+NFmJesc7StpkquZk+WJFCaL0Wp//2sa0=
|
||||
github.com/anacrolix/missinggo/v2 v2.10.0 h1:pg0iO4Z/UhP2MAnmGcaMtp5ZP9kyWsusENWN9aolrkY=
|
||||
github.com/anacrolix/missinggo/v2 v2.10.0/go.mod h1:nCRMW6bRCMOVcw5z9BnSYKF+kDbtenx+hQuphf4bK8Y=
|
||||
github.com/anacrolix/mmsg v1.0.1 h1:TxfpV7kX70m3f/O7ielL/2I3OFkMPjrRCPo7+4X5AWw=
|
||||
github.com/anacrolix/mmsg v1.0.1/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc=
|
||||
github.com/anacrolix/multiless v0.4.0 h1:lqSszHkliMsZd2hsyrDvHOw4AbYWa+ijQ66LzbjqWjM=
|
||||
@@ -79,15 +90,21 @@ github.com/anacrolix/multiless v0.4.0/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE4
|
||||
github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg=
|
||||
github.com/anacrolix/stm v0.4.0 h1:tOGvuFwaBjeu1u9X1eIh9TX8OEedEiEQ1se1FjhFnXY=
|
||||
github.com/anacrolix/stm v0.4.0/go.mod h1:GCkwqWoAsP7RfLW+jw+Z0ovrt2OO7wRzcTtFYMYY5t8=
|
||||
github.com/anacrolix/stm v0.5.0 h1:9df1KBpttF0TzLgDq51Z+TEabZKMythqgx89f1FQJt8=
|
||||
github.com/anacrolix/stm v0.5.0/go.mod h1:MOwrSy+jCm8Y7HYfMAwPj7qWVu7XoVvjOiYwJmpeB/M=
|
||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
|
||||
github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
||||
github.com/anacrolix/sync v0.5.1 h1:FbGju6GqSjzVoTgcXTUKkF041lnZkG5P0C3T5RL3SGc=
|
||||
github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
||||
github.com/anacrolix/sync v0.5.4 h1:yXZLIjXh/G+Rh2mYGCAPmszmF/fvEPadDy7/pPChpKM=
|
||||
github.com/anacrolix/sync v0.5.4/go.mod h1:21cUWerw9eiu/3T3kyoChu37AVO+YFue1/H15qqubS0=
|
||||
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.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
||||
github.com/anacrolix/torrent v1.58.1 h1:6FP+KH57b1gyT2CpVL9fEqf9MGJEgh3xw1VA8rI0pW8=
|
||||
github.com/anacrolix/torrent v1.58.1/go.mod h1:/7ZdLuHNKgtCE1gjYJCfbtG9JodBcDaF5ip5EUWRtk8=
|
||||
github.com/anacrolix/torrent v1.59.1 h1:Z8wyvYc42EIm5OR7TsnKoFp6t4T7y1OIUoBgwsidKyA=
|
||||
github.com/anacrolix/torrent v1.59.1/go.mod h1:4yT/cQCiAk4/hL3kZawq/dUUgND8FWIcolYlfnQ4P9M=
|
||||
github.com/anacrolix/upnp v0.1.4 h1:+2t2KA6QOhm/49zeNyeVwDu1ZYS9dB9wfxyVvh/wk7U=
|
||||
github.com/anacrolix/upnp v0.1.4/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
|
||||
github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4=
|
||||
@@ -103,11 +120,15 @@ github.com/antchfx/xpath v1.3.3/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwq
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
||||
github.com/benbjohnson/immutable v0.3.0 h1:TVRhuZx2wG9SZ0LRdqlbs9S5BZ6Y24hJEHTCgWHZEIw=
|
||||
github.com/benbjohnson/immutable v0.3.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
||||
github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d h1:2qVb9bsAMtmAfnxXltm+6eBzrrS7SZ52c3SedsulaMI=
|
||||
github.com/benbjohnson/immutable v0.4.1-0.20221220213129-8932b999621d/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM=
|
||||
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.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
@@ -116,6 +137,8 @@ github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Y
|
||||
github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4=
|
||||
github.com/blinkbean/dingtalk v1.1.3/go.mod h1:9BaLuGSBqY3vT5hstValh48DbsKO7vaHaJnG9pXwbto=
|
||||
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
|
||||
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
|
||||
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-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||
@@ -133,8 +156,8 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyruzin/golang-tmdb v1.6.3 h1:TKK9h+uuwiDOaFlsVispG1KxqhsSM5Y4ZELnUF3GlqU=
|
||||
github.com/cyruzin/golang-tmdb v1.6.3/go.mod h1:ZSryJLCcY+9TiKU+LbouXKns++YBrM8Tizannr05c+I=
|
||||
github.com/cyruzin/golang-tmdb v1.8.1 h1:5s0FjKM5NsTfezvIkZKUgAEw0eBHs1t2JmuJ6Gy81sg=
|
||||
github.com/cyruzin/golang-tmdb v1.8.1/go.mod h1:Yx4f4KyLgWAnvwgZ729nJPOTKkD4epYoK+cGDZ3AFzs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -153,18 +176,18 @@ github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7z
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
|
||||
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
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/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4=
|
||||
github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
|
||||
github.com/gin-contrib/zap v1.1.3 h1:9e/U9fYd4/OBfmSEBs5hHZq114uACn7bpuzvCkcJySA=
|
||||
github.com/gin-contrib/zap v1.1.3/go.mod h1:+BD/6NYZKJyUpqVoJEvgeq9GLz8pINEQvak9LHNOTSE=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
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-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||
@@ -177,6 +200,8 @@ github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916 h1:OyQmpAN302w
|
||||
github.com/go-llsqlite/adapter v0.0.0-20230927005056-7f5ce7f0c916/go.mod h1:DADrR88ONKPPeSGjFp5iEN55Arx3fi2qXZeKCYDpbmU=
|
||||
github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568 h1:3EpZo8LxIzF4q3BT+vttQQlRfA6uTtTb/cxVisWa5HM=
|
||||
github.com/go-llsqlite/crawshaw v0.5.2-0.20240425034140-f30eb7704568/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYzd38ICggWqtaE=
|
||||
github.com/go-llsqlite/crawshaw v0.5.6-0.20250312230104-194977a03421 h1:GClwZI0at7xwV0TpgUMTYr/DoTE7TJZ/tc29LcPcs7o=
|
||||
github.com/go-llsqlite/crawshaw v0.5.6-0.20250312230104-194977a03421/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYzd38ICggWqtaE=
|
||||
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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -201,10 +226,12 @@ github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaEL
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
||||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
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.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gocolly/colly v1.2.0 h1:qRz9YAn8FIH0qzgNUw+HT9UN7wm1oF9OBAilwEWpyrI=
|
||||
github.com/gocolly/colly v1.2.0/go.mod h1:Hof5T3ZswNVsOHYmba1u03W65HDWgpV5HifSuueE0EA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
@@ -221,7 +248,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
@@ -261,8 +287,6 @@ github.com/gregdel/pushover v1.3.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
|
||||
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
|
||||
github.com/hekmon/cunits/v2 v2.1.0 h1:k6wIjc4PlacNOHwKEMBgWV2/c8jyD4eRMs5mR1BBhI0=
|
||||
@@ -278,8 +302,6 @@ github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq
|
||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
@@ -313,12 +335,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
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-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@@ -326,8 +344,6 @@ github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
|
||||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -347,20 +363,20 @@ github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||
github.com/ncruces/go-sqlite3 v0.18.4 h1:Je8o3y33MDwPYY/Cacas8yCsuoUzpNY/AgoSlN2ekyE=
|
||||
github.com/ncruces/go-sqlite3 v0.18.4/go.mod h1:4HLag13gq1k10s4dfGBhMfRVsssJRT9/5hYqVM9RUYo=
|
||||
github.com/ncruces/go-sqlite3 v0.28.0 h1:AQVTUPgfamONl09LS+4rGFbHmLKM8/QrJJJi1UukjEQ=
|
||||
github.com/ncruces/go-sqlite3 v0.28.0/go.mod h1:WqvLhYwtEiZzg1H8BIeahUv/DxbmR+3xG5jDHDiBAGk=
|
||||
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
|
||||
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
|
||||
github.com/nikoksr/notify v1.0.0 h1:qe9/6FRsWdxBgQgWcpvQ0sv8LRGJZDpRB4TkL2uNdO8=
|
||||
github.com/nikoksr/notify v1.0.0/go.mod h1:hPaaDt30d6LAA7/5nb0e48Bp/MctDfycCSs8VEgN29I=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/nikoksr/notify v1.3.0 h1:UxzfxzAYGQD9a5JYLBTVx0lFMxeHCke3rPCkfWdPgLs=
|
||||
github.com/nikoksr/notify v1.3.0/go.mod h1:Xor2hMmkvrCfkCKvXGbcrESez4brac2zQjhd6U2BbeM=
|
||||
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/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0=
|
||||
github.com/openai/openai-go v1.12.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
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/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA=
|
||||
@@ -369,18 +385,20 @@ github.com/pion/dtls/v3 v3.0.3 h1:j5ajZbQwff7Z8k3pE3S+rQ4STvKvXUdKsi/07ka+OWM=
|
||||
github.com/pion/dtls/v3 v3.0.3/go.mod h1:weOTUyIV4z0bQaVzKe8kpaP17+us3yAuiQsEAG1STMU=
|
||||
github.com/pion/ice/v4 v4.0.2 h1:1JhBRX8iQLi0+TfcavTjPjI6GO41MFn4CeTBX+Y9h5s=
|
||||
github.com/pion/ice/v4 v4.0.2/go.mod h1:DCdqyzgtsDNYN6/3U8044j3U7qsJ9KFJC92VnOWHvXg=
|
||||
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
|
||||
github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/interceptor v0.1.39 h1:Y6k0bN9Y3Lg/Wb21JBWp480tohtns8ybJ037AGr9UuA=
|
||||
github.com/pion/interceptor v0.1.39/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic=
|
||||
github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4=
|
||||
github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic=
|
||||
github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
|
||||
github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
|
||||
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
|
||||
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE=
|
||||
github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||
github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk=
|
||||
github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
|
||||
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
|
||||
github.com/pion/rtp v1.8.18 h1:yEAb4+4a8nkPCecWzQB6V/uEU18X1lQCGAQCjP+pyvU=
|
||||
github.com/pion/rtp v1.8.18/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
|
||||
github.com/pion/sctp v1.8.33 h1:dSE4wX6uTJBcNm8+YlMg7lw1wqyKHggsP5uKbdj+NZw=
|
||||
github.com/pion/sctp v1.8.33/go.mod h1:beTnqSzewI53KWoG3nqB282oDMGrhNxBdb+JZnkCwRM=
|
||||
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
|
||||
@@ -436,10 +454,8 @@ github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v
|
||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/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/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
@@ -455,16 +471,14 @@ github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIK
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
|
||||
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
@@ -480,18 +494,29 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg=
|
||||
github.com/temoto/robotstxt v1.1.2/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
|
||||
github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g=
|
||||
github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=
|
||||
github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
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.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
@@ -499,27 +524,27 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
|
||||
github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||
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/wlynxg/anet v0.0.3 h1:PvR53psxFXstc12jelG6f1Lv4MWqE0tI76/hHGjh9rg=
|
||||
github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
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/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA=
|
||||
github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk=
|
||||
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
|
||||
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
|
||||
github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
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.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
|
||||
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
|
||||
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
|
||||
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
|
||||
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
|
||||
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
|
||||
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
|
||||
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
|
||||
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
|
||||
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
|
||||
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
@@ -538,12 +563,12 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
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-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
|
||||
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
||||
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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -555,8 +580,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -566,10 +591,8 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
@@ -580,8 +603,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
|
||||
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
|
||||
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/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -597,8 +620,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -626,8 +649,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
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=
|
||||
@@ -641,7 +664,6 @@ golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
@@ -651,10 +673,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -667,20 +689,15 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golift.io/starr v1.0.0 h1:IDSaSL+ZYxdLT/Lg//dg/iwZ39LHO3D5CmbLCOgSXbI=
|
||||
golift.io/starr v1.0.0/go.mod h1:xnUwp4vK62bDvozW9QHUYc08m6kjwaZnGw3Db65fQHw=
|
||||
golift.io/starr v1.1.0 h1:KTAecOEne/zKQvrh8mcfEA7YlQ39FnvjZRIhJSIvxL4=
|
||||
golift.io/starr v1.1.0/go.mod h1:WnLkyfF7X2q676mXriGMZQrBA3wGt1BjA2qdxMmA/wg=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
@@ -706,8 +723,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
||||
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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
|
||||
@@ -3,6 +3,7 @@ package log
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"polaris/pkg/utils"
|
||||
"strings"
|
||||
|
||||
"github.com/natefinch/lumberjack"
|
||||
@@ -13,7 +14,9 @@ import (
|
||||
var sugar *zap.SugaredLogger
|
||||
var atom zap.AtomicLevel
|
||||
|
||||
const dataPath = "./data"
|
||||
func init() {
|
||||
InitLogger(false)
|
||||
}
|
||||
|
||||
func InitLogger(toFile bool) {
|
||||
atom = zap.NewAtomicLevel()
|
||||
@@ -22,7 +25,7 @@ func InitLogger(toFile bool) {
|
||||
w := zapcore.Lock(os.Stdout)
|
||||
if toFile {
|
||||
w = zapcore.AddSync(&lumberjack.Logger{
|
||||
Filename: filepath.Join(dataPath, "logs", "polaris.log"),
|
||||
Filename: filepath.Join(utils.GetUserDataDir(), "logs", "polaris.log"),
|
||||
MaxSize: 50, // megabytes
|
||||
MaxBackups: 3,
|
||||
MaxAge: 30, // days
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
func NewDownloader(downloadDir string) (*Downloader, error) {
|
||||
cfg := torrent.NewDefaultClientConfig()
|
||||
cfg.DataDir = downloadDir
|
||||
cfg.ListenPort = 51243
|
||||
//cfg.ListenPort = 51243
|
||||
t, err := torrent.NewClient(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "create torrent client")
|
||||
|
||||
171
pkg/deepseek/deepseek.go
Normal file
171
pkg/deepseek/deepseek.go
Normal file
@@ -0,0 +1,171 @@
|
||||
package deepseek
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"polaris/log"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/openai/openai-go"
|
||||
"github.com/openai/openai-go/option"
|
||||
)
|
||||
|
||||
func NewClient(apiKey string) *Client {
|
||||
r := openai.NewClient(option.WithAPIKey(apiKey), option.WithBaseURL("https://api.deepseek.com"))
|
||||
return &Client{openai: &r, model: "deepseek-chat"}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
openai *openai.Client
|
||||
model string
|
||||
}
|
||||
|
||||
func (c *Client) Test() error {
|
||||
|
||||
question := `What computer ran the first neural network?
|
||||
EXAMPLE JSON OUTPUT:
|
||||
{
|
||||
"origin": "The origin of the computer",
|
||||
"full_name": "The name of the device model",
|
||||
"legacy": "Its influence on the field of computing",
|
||||
"notable_facts": "A few key facts about the computer
|
||||
}
|
||||
`
|
||||
|
||||
chat, err_ := c.openai.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
|
||||
// ...
|
||||
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
|
||||
OfJSONSchema: &openai.ResponseFormatJSONSchemaParam{
|
||||
Type: "json_object",
|
||||
},
|
||||
},
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.UserMessage(question),
|
||||
},
|
||||
|
||||
// only certain models can perform structured outputs
|
||||
Model: c.model,
|
||||
})
|
||||
if err_ != nil {
|
||||
return err_
|
||||
}
|
||||
|
||||
log.Infof("%+v", chat.Choices[0].Message.Content)
|
||||
// extract into a well-typed struct
|
||||
return nil
|
||||
}
|
||||
|
||||
type Movies struct {
|
||||
Movies []struct {
|
||||
Name string `json:"name"`
|
||||
Match string `json:"match"`
|
||||
} `json:"movies"`
|
||||
}
|
||||
|
||||
type Tvs struct {
|
||||
Tvs []Tv `json:"tvs"`
|
||||
}
|
||||
|
||||
type Tv struct {
|
||||
Name string `json:"name"`
|
||||
FileName string `json:"file_name"`
|
||||
Match string `json:"match"`
|
||||
Season string `json:"season"`
|
||||
StartEpisode string `json:"start_episode"`
|
||||
EndEpisode string `json:"end_episode"`
|
||||
Quality string `json:"quality"`
|
||||
IsSeasonPackage string `json:"is_season_package"`
|
||||
}
|
||||
|
||||
func (c *Client) AssessMovieNames(movieName string, releaseYear int, torrentNames []string) (*Movies, error) {
|
||||
q := `用户输入的是一些文件名称,你需要判断哪些文件可能属于 %d 年的电影 %s,哪些可能不是。
|
||||
|
||||
EXAMPLE JSON OUTPUT:
|
||||
{
|
||||
"movies": [
|
||||
{
|
||||
"name": "The name of the movie",
|
||||
"match": "true or false"
|
||||
},
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
q = fmt.Sprintf(q, releaseYear, movieName)
|
||||
chat, err_ := c.openai.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
|
||||
//
|
||||
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
|
||||
OfJSONSchema: &openai.ResponseFormatJSONSchemaParam{
|
||||
Type: "json_object",
|
||||
},
|
||||
},
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(q),
|
||||
openai.UserMessage(fmt.Sprintf("文件名称: %v", torrentNames)),
|
||||
},
|
||||
|
||||
// only certain models can perform structured outputs
|
||||
Model: c.model,
|
||||
})
|
||||
if err_ != nil {
|
||||
return nil, err_
|
||||
}
|
||||
|
||||
log.Infof("%+v", chat.Choices[0].Message.Content)
|
||||
var res Movies
|
||||
if err := json.Unmarshal([]byte(chat.Choices[0].Message.Content), &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// extract into a well-typed struct
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (c *Client) AssessTvNames(tvName string, releaseYear int, torrentNames []string) ([]Tv, error) {
|
||||
log.Debugf("deepseek tv name: %s, year: %d, torrent name len: %v", tvName, releaseYear, len(torrentNames))
|
||||
t := time.Now()
|
||||
defer func() {
|
||||
log.Infof("deepseek assess tv name cost: %v", time.Since(t))
|
||||
}()
|
||||
|
||||
q := `用户输入的是一些文件名称,你需要判断哪些文件可能属于 %d 年的电视剧 %s,哪些可能不是,并返回匹配的文件名。
|
||||
|
||||
EXAMPLE JSON OUTPUT:
|
||||
{
|
||||
"tvs": [
|
||||
"matched file name 1", "matched file name 2", ...
|
||||
]
|
||||
}`
|
||||
q = fmt.Sprintf(q, releaseYear, tvName)
|
||||
|
||||
var res []Tv
|
||||
|
||||
chat, err_ := c.openai.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
|
||||
MaxTokens: openai.Opt(int64(4096)),
|
||||
//...
|
||||
ResponseFormat: openai.ChatCompletionNewParamsResponseFormatUnion{
|
||||
OfJSONSchema: &openai.ResponseFormatJSONSchemaParam{
|
||||
Type: "json_object",
|
||||
},
|
||||
},
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(q),
|
||||
openai.UserMessage(fmt.Sprintf("文件名称: %v", torrentNames)),
|
||||
},
|
||||
|
||||
// only certain models can perform structured outputs
|
||||
Model: c.model,
|
||||
})
|
||||
if err_ != nil {
|
||||
return nil, err_
|
||||
}
|
||||
log.Infof("%+v", chat.Choices[0].Message.Content)
|
||||
var tvs Tvs
|
||||
if err := json.Unmarshal([]byte(chat.Choices[0].Message.Content), &tvs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, tvs.Tvs...)
|
||||
|
||||
return res, nil
|
||||
}
|
||||
11
pkg/deepseek/deepseek_test.go
Normal file
11
pkg/deepseek/deepseek_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package deepseek
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDeepseek(t *testing.T) {
|
||||
r := NewClient("sk-")
|
||||
_, err := r.AssessTvNames("基督山伯爵", 2025, []string{"The Count of Monte Cristo 2024 S01 1080p WEB-DL DD 5.1 H.264-playWEB", "The Count of Monte Cristo 2024 S01E06-08 MULTi 1080p WEB H264-AMB3R"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
@@ -93,6 +94,28 @@ func (client *Client) get(endpoint string, opts map[string]string) (*http.Respon
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (cleint *Client) postJson(endpoint string, body any) (*http.Response, error) {
|
||||
var buff bytes.Buffer
|
||||
buff.WriteString("json=")
|
||||
d, err := json.Marshal(body)
|
||||
if err!= nil {
|
||||
return nil, err
|
||||
}
|
||||
buff.Write(d)
|
||||
log.Println(buff.String())
|
||||
req, err := http.NewRequest("POST", cleint.URL+endpoint, &buff)
|
||||
if err!= nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("User-Agent", "go-qbittorrent v0.1")
|
||||
resp, err := cleint.http.Do(req)
|
||||
if err!= nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// post will perform a POST request with no content-type specified
|
||||
func (client *Client) post(endpoint string, opts map[string]string) (*http.Response, error) {
|
||||
// add optional parameters that the user wants
|
||||
@@ -315,8 +338,9 @@ func (client *Client) Preferences() (prefs Preferences, err error) {
|
||||
}
|
||||
|
||||
// SetPreferences of the qbittorrent client
|
||||
func (client *Client) SetPreferences() (prefsSet bool, err error) {
|
||||
resp, err := client.post("api/v2/app/setPreferences", nil)
|
||||
func (client *Client) SetPreferences(m map[string]any) (prefsSet bool, err error) {
|
||||
|
||||
resp, err := client.postJson("api/v2/app/setPreferences", m)
|
||||
return (resp.Status == "200 OK"), err
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MovieMetadata struct {
|
||||
@@ -15,7 +16,7 @@ type MovieMetadata struct {
|
||||
IsQingban bool
|
||||
}
|
||||
|
||||
func (m *MovieMetadata) IsAcceptable(names... string) bool {
|
||||
func (m *MovieMetadata) IsAcceptable(names ...string) bool {
|
||||
for _, name := range names {
|
||||
re := regexp.MustCompile(`[^\p{L}\w\s]`)
|
||||
name = re.ReplaceAllString(strings.ToLower(name), " ")
|
||||
@@ -26,41 +27,63 @@ func (m *MovieMetadata) IsAcceptable(names... string) bool {
|
||||
re := regexp.MustCompile(`\b` + name + `\b`)
|
||||
return re.MatchString(name2)
|
||||
}
|
||||
|
||||
if strings.Contains(name2, name) {
|
||||
|
||||
if strings.Contains(name2, name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
func ParseMovie(name string) *MovieMetadata {
|
||||
name = strings.Join(strings.Fields(name), " ") //remove unnessary spaces
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
var meta = &MovieMetadata{}
|
||||
func findYear(name string) (year int, index int) {
|
||||
yearRe := regexp.MustCompile(`\(\d{4}\)`)
|
||||
yearMatches := yearRe.FindAllString(name, -1)
|
||||
var yearIndex = -1
|
||||
index = -1
|
||||
if len(yearMatches) > 0 {
|
||||
yearIndex = strings.Index(name, yearMatches[0])
|
||||
index = strings.Index(name, yearMatches[0])
|
||||
y := yearMatches[0][1 : len(yearMatches[0])-1]
|
||||
n, err := strconv.Atoi(y)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("convert %s error: %v", y, err))
|
||||
}
|
||||
meta.Year = n
|
||||
year = n
|
||||
} else {
|
||||
yearRe := regexp.MustCompile(`\d{4}`)
|
||||
yearMatches := yearRe.FindAllString(name, -1)
|
||||
if len(yearMatches) > 0 {
|
||||
n, err := strconv.Atoi(yearMatches[0])
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("convert %s error: %v", yearMatches[0], err))
|
||||
}
|
||||
meta.Year = n
|
||||
year, index = findYearInMatches(yearMatches, name)
|
||||
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func findYearInMatches(matches []string, name string) (year int, index int) {
|
||||
if len(matches) == 0 {
|
||||
return 0, -1
|
||||
}
|
||||
for _, y := range matches {
|
||||
index = strings.Index(name, y)
|
||||
n, err := strconv.Atoi(y)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("convert %s error: %v", y, err))
|
||||
}
|
||||
if n < 1900 || n > time.Now().Year()+1 { //filter invalid year
|
||||
continue
|
||||
}
|
||||
year = n
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParseMovie(name string) *MovieMetadata {
|
||||
name = strings.Join(strings.Fields(name), " ") //remove unnessary spaces
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
var meta = &MovieMetadata{}
|
||||
year, yearIndex := findYear(name)
|
||||
|
||||
meta.Year = year
|
||||
|
||||
if yearIndex != -1 {
|
||||
meta.Name = name[:yearIndex]
|
||||
@@ -78,7 +101,7 @@ func ParseMovie(name string) *MovieMetadata {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Pirated_movie_release_types
|
||||
func isQiangban(name string) bool {
|
||||
qiangbanFilter := []string{"CAMRip","CAM-Rip", "CAM", "HDCAM", "TS","TSRip", "HDTS", "TELESYNC", "PDVD", "PreDVDRip", "TC", "HDTC", "TELECINE", "WP", "WORKPRINT"}
|
||||
qiangbanFilter := []string{"CAMRip", "CAM-Rip", "CAM", "HDCAM", "TS", "TSRip", "HDTS", "TELESYNC", "PDVD", "PreDVDRip", "TC", "HDTC", "TELECINE", "WP", "WORKPRINT"}
|
||||
re := regexp.MustCompile(`\W`)
|
||||
name = re.ReplaceAllString(strings.ToLower(name), " ")
|
||||
fields := strings.Fields(name)
|
||||
|
||||
@@ -272,7 +272,7 @@ func matchResolution(s string) string {
|
||||
|
||||
func maybeSeasonPack(s string) bool {
|
||||
//season pack
|
||||
packRe := regexp.MustCompile(`((\d{1,2}-\d{1,2}))|(complete)|(全集)`)
|
||||
packRe := regexp.MustCompile(`((\d{1,2}-\d{1,2}))|(complete)|(全集)|(合集)|(\W[sS]\d{1,2}\W)`)
|
||||
if packRe.MatchString(s) {
|
||||
return true
|
||||
}
|
||||
@@ -409,6 +409,8 @@ func parseName(name string) *Info {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return meta
|
||||
}
|
||||
year, yearP := findYear(name)
|
||||
meta.Year = year
|
||||
|
||||
season, p := findSeason(name)
|
||||
if season == -1 {
|
||||
@@ -437,7 +439,11 @@ func parseName(name string) *Info {
|
||||
|
||||
//tv name
|
||||
if utils.IsASCII(name) && p < len(name) && p-1 > 0 {
|
||||
meta.NameEn = strings.TrimSpace(name[:p-1])
|
||||
p1 := p -1
|
||||
if yearP > 0 {
|
||||
p1 = min(p1, yearP-1)
|
||||
}
|
||||
meta.NameEn = strings.TrimSpace(name[:p1])
|
||||
meta.NameCn = meta.NameEn
|
||||
} else {
|
||||
fields := strings.FieldsFunc(name, func(r rune) bool {
|
||||
|
||||
@@ -197,6 +197,25 @@ func Test_ParseTV18(t *testing.T) {
|
||||
//assert.Equal(t, "720p", m.Resolution)
|
||||
}
|
||||
|
||||
//The Count of Monte Cristo 2024 S01 1080p WEB-DL DD 5.1 H.264-playWEB
|
||||
func Test_ParseTV20(t *testing.T) {
|
||||
s1 := "The Count of Monte Cristo 2024 S01 1080p WEB-DL DD 5.1 H.264-playWEB "
|
||||
m := ParseTv(s1)
|
||||
log.Infof("results: %+v", m)
|
||||
assert.Equal(t, 1, m.Season)
|
||||
assert.Equal(t, true, m.IsSeasonPack)
|
||||
}
|
||||
|
||||
|
||||
func Test_ParseTV21(t *testing.T) {
|
||||
s1 := "【东京不够热】基督山伯爵-华丽的复仇-【01~09】【1280x720】【简中/日双语字幕】【2018春季日剧】【合集】 "
|
||||
m := ParseTv(s1)
|
||||
log.Infof("results: %+v", m)
|
||||
assert.Equal(t, 1, m.Season)
|
||||
assert.Equal(t, 2018, m.Year)
|
||||
assert.Equal(t, true, m.IsSeasonPack)
|
||||
}
|
||||
|
||||
// The Day of the Jackal (Season 1) WEB-DL 1080p
|
||||
func Test_ParseTV19(t *testing.T) {
|
||||
s1 := "The Day of the Jackal (Season 1) WEB-DL 1080p "
|
||||
|
||||
31
pkg/nat/cmd/main.go
Normal file
31
pkg/nat/cmd/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"polaris/log"
|
||||
"polaris/pkg/nat"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// This is a placeholder for the main function.
|
||||
// The actual implementation will depend on the specific requirements of the application.
|
||||
src, err := net.Listen("tcp", ":8080")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := src.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Infof("new connection: %+v", conn)
|
||||
dest, err := net.Dial("tcp", "10.0.0.8:8080")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go nat.ReverseProxy(conn, dest)
|
||||
}
|
||||
select {}
|
||||
}
|
||||
67
pkg/nat/reverse_proxy.go
Normal file
67
pkg/nat/reverse_proxy.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package nat
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
func ReverseProxy(sourceConn net.Conn, targetConn net.Conn) {
|
||||
serverClosed := make(chan struct{}, 1)
|
||||
clientClosed := make(chan struct{}, 1)
|
||||
|
||||
go broker(sourceConn, targetConn, clientClosed)
|
||||
go broker(targetConn, sourceConn, serverClosed)
|
||||
|
||||
// wait for one half of the proxy to exit, then trigger a shutdown of the
|
||||
// other half by calling CloseRead(). This will break the read loop in the
|
||||
// broker and allow us to fully close the connection cleanly without a
|
||||
// "use of closed network connection" error.
|
||||
var waitFor chan struct{}
|
||||
select {
|
||||
case <-clientClosed:
|
||||
// the client closed first and any more packets from the server aren't
|
||||
// useful, so we can optionally SetLinger(0) here to recycle the port
|
||||
// faster.
|
||||
waitFor = serverClosed
|
||||
case <-serverClosed:
|
||||
waitFor = clientClosed
|
||||
}
|
||||
|
||||
// Wait for the other connection to close.
|
||||
// This "waitFor" pattern isn't required, but gives us a way to track the
|
||||
// connection and ensure all copies terminate correctly; we can trigger
|
||||
// stats on entry and deferred exit of this function.
|
||||
<-waitFor
|
||||
}
|
||||
|
||||
func pipe(src net.Conn, dest net.Conn) {
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := io.Copy(src, dest)
|
||||
errChan <- err
|
||||
}()
|
||||
go func() {
|
||||
_, err := io.Copy(dest, src)
|
||||
errChan <- err
|
||||
}()
|
||||
<-errChan
|
||||
}
|
||||
|
||||
// This does the actual data transfer.
|
||||
// The broker only closes the Read side.
|
||||
func broker(dst, src net.Conn, srcClosed chan struct{}) {
|
||||
// We can handle errors in a finer-grained manner by inlining io.Copy (it's
|
||||
// simple, and we drop the ReaderFrom or WriterTo checks for
|
||||
// net.Conn->net.Conn transfers, which aren't needed). This would also let
|
||||
// us adjust buffersize.
|
||||
_, err := io.Copy(dst, src)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Copy error: %s", err)
|
||||
}
|
||||
if err := src.Close(); err != nil {
|
||||
log.Printf("Close error: %s", err)
|
||||
}
|
||||
srcClosed <- struct{}{}
|
||||
}
|
||||
169
pkg/nat/stun.go
Normal file
169
pkg/nat/stun.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package nat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"polaris/log"
|
||||
|
||||
"github.com/pion/stun/v3"
|
||||
)
|
||||
|
||||
func getNatIpAndPort() (*stun.XORMappedAddress, error) {
|
||||
|
||||
var xorAddr stun.XORMappedAddress
|
||||
|
||||
for _, server := range getStunServers() {
|
||||
log.Infof("try to connect to stun server: %s", server)
|
||||
u, err := stun.ParseURI("stun:" + server)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Creating a "connection" to STUN server.
|
||||
c, err := stun.DialURI(u, &stun.DialConfig{})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Building binding request with random transaction id.
|
||||
message := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
|
||||
// Sending request to STUN server, waiting for response message.
|
||||
var err1 error
|
||||
if err := c.Do(message, func(res stun.Event) {
|
||||
if res.Error != nil {
|
||||
err1 = res.Error
|
||||
return
|
||||
}
|
||||
log.Infof("stun server %s response: %v", server, res.Message.String())
|
||||
// Decoding XOR-MAPPED-ADDRESS attribute from message.
|
||||
|
||||
if err := xorAddr.GetFrom(res.Message); err != nil {
|
||||
err1 = err
|
||||
return
|
||||
}
|
||||
fmt.Println("your IP is", xorAddr.IP)
|
||||
fmt.Println("your port is", xorAddr.Port)
|
||||
}); err != nil {
|
||||
log.Warnf("stun server %s error: %v", server, err)
|
||||
continue
|
||||
}
|
||||
if err1 != nil {
|
||||
log.Warnf("stun server %s error: %v", server, err1)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return &xorAddr, nil
|
||||
}
|
||||
|
||||
func getStunServers() []string {
|
||||
var servers []string
|
||||
for _, line := range strings.Split(strings.TrimSpace(stunServers1), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
servers = append(servers, line)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
// https://github.com/heiher/natmap/issues/18
|
||||
const stunServers1 = `
|
||||
stun.miwifi.com:3478
|
||||
stun.chat.bilibili.com:3478
|
||||
stun.cloudflare.com:3478
|
||||
turn.cloudflare.com:3478
|
||||
fwa.lifesizecloud.com:3478
|
||||
`
|
||||
|
||||
// https://github.com/pradt2/always-online-stun
|
||||
const stunServers = `
|
||||
stun.miwifi.com:3478
|
||||
stun.ukh.de:3478
|
||||
stun.kanojo.de:3478
|
||||
stun.m-online.net:3478
|
||||
stun.nextcloud.com:3478
|
||||
stun.voztovoice.org:3478
|
||||
stun.oncloud7.ch:3478
|
||||
stun.antisip.com:3478
|
||||
stun.bitburger.de:3478
|
||||
stun.acronis.com:3478
|
||||
stun.signalwire.com:3478
|
||||
stun.sonetel.net:3478
|
||||
stun.poetamatusel.org:3478
|
||||
stun.avigora.fr:3478
|
||||
stun.diallog.com:3478
|
||||
stun.nanocosmos.de:3478
|
||||
stun.romaaeterna.nl:3478
|
||||
stun.heeds.eu:3478
|
||||
stun.freeswitch.org:3478
|
||||
stun.engineeredarts.co.uk:3478
|
||||
stun.root-1.de:3478
|
||||
stun.healthtap.com:3478
|
||||
stun.allflac.com:3478
|
||||
stun.vavadating.com:3478
|
||||
stun.godatenow.com:3478
|
||||
stun.mixvoip.com:3478
|
||||
stun.sip.us:3478
|
||||
stun.sipthor.net:3478
|
||||
stun.stochastix.de:3478
|
||||
stun.kaseya.com:3478
|
||||
stun.files.fm:3478
|
||||
stun.meetwife.com:3478
|
||||
stun.myspeciality.com:3478
|
||||
stun.3wayint.com:3478
|
||||
stun.voip.blackberry.com:3478
|
||||
stun.axialys.net:3478
|
||||
stun.bridesbay.com:3478
|
||||
stun.threema.ch:3478
|
||||
stun.siptrunk.com:3478
|
||||
stun.ncic.com:3478
|
||||
stun.1cbit.ru:3478
|
||||
stun.ttmath.org:3478
|
||||
stun.yesdates.com:3478
|
||||
stun.sonetel.com:3478
|
||||
stun.peethultra.be:3478
|
||||
stun.pure-ip.com:3478
|
||||
stun.business-isp.nl:3478
|
||||
stun.ringostat.com:3478
|
||||
stun.imp.ch:3478
|
||||
stun.cope.es:3478
|
||||
stun.baltmannsweiler.de:3478
|
||||
stun.lovense.com:3478
|
||||
stun.frozenmountain.com:3478
|
||||
stun.linuxtrent.it:3478
|
||||
stun.thinkrosystem.com:3478
|
||||
stun.3deluxe.de:3478
|
||||
stun.skydrone.aero:3478
|
||||
stun.ru-brides.com:3478
|
||||
stun.streamnow.ch:3478
|
||||
stun.atagverwarming.nl:3478
|
||||
stun.ipfire.org:3478
|
||||
stun.fmo.de:3478
|
||||
stun.moonlight-stream.org:3478
|
||||
stun.f.haeder.net:3478
|
||||
stun.nextcloud.com:443
|
||||
stun.finsterwalder.com:3478
|
||||
stun.voipia.net:3478
|
||||
stun.zepter.ru:3478
|
||||
stun.sipnet.net:3478
|
||||
stun.hot-chilli.net:3478
|
||||
stun.zentauron.de:3478
|
||||
stun.geesthacht.de:3478
|
||||
stun.annatel.net:3478
|
||||
stun.flashdance.cx:3478
|
||||
stun.voipgate.com:3478
|
||||
stun.genymotion.com:3478
|
||||
stun.graftlab.com:3478
|
||||
stun.fitauto.ru:3478
|
||||
stun.telnyx.com:3478
|
||||
stun.verbo.be:3478
|
||||
stun.dcalling.de:3478
|
||||
stun.lleida.net:3478
|
||||
stun.romancecompass.com:3478
|
||||
stun.siplogin.de:3478
|
||||
stun.bethesda.net:3478
|
||||
stun.alpirsbacher.de:3478
|
||||
stun.uabrides.com:3478
|
||||
stun.technosens.fr:3478
|
||||
stun.radiojar.com:3478
|
||||
`
|
||||
14
pkg/nat/stun_test.go
Normal file
14
pkg/nat/stun_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package nat
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestStun1(t *testing.T) {
|
||||
// s,err := getNatIpAndPort()
|
||||
// if err != nil {
|
||||
// t.Logf("get nat ip and port error: %v", err)
|
||||
// t.Fail()
|
||||
// }
|
||||
|
||||
//NatTraversal()
|
||||
t.Logf("nat ip: ")
|
||||
}
|
||||
204
pkg/nat/traversal.go
Normal file
204
pkg/nat/traversal.go
Normal file
@@ -0,0 +1,204 @@
|
||||
package nat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"polaris/log"
|
||||
"time"
|
||||
|
||||
"github.com/pion/stun/v3"
|
||||
)
|
||||
|
||||
const (
|
||||
udp = "udp4"
|
||||
pingMsg = "ping"
|
||||
pongMsg = "pong"
|
||||
timeoutMillis = 500
|
||||
)
|
||||
|
||||
func NewNatTraversal(addrCallback func(stun.XORMappedAddress) error, targetHost string) (*NatTraversal, error) {
|
||||
conn, err := net.ListenUDP(udp, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listen: %w", err)
|
||||
}
|
||||
|
||||
log.Infof("Listening on %s", conn.LocalAddr())
|
||||
|
||||
messageChan := listen(conn)
|
||||
s := &NatTraversal{
|
||||
conn: conn,
|
||||
messageChan: messageChan,
|
||||
cancel: make(chan struct{}),
|
||||
addrChan: make(chan stun.XORMappedAddress),
|
||||
addrCallback: addrCallback,
|
||||
targetHost: targetHost,
|
||||
}
|
||||
|
||||
go s.updateNatAddr()
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type NatTraversal struct {
|
||||
//peerAddr *net.UDPAddr
|
||||
conn *net.UDPConn
|
||||
messageChan <-chan []byte
|
||||
addrChan chan stun.XORMappedAddress
|
||||
cancel chan struct{}
|
||||
|
||||
stunAddr *stun.XORMappedAddress
|
||||
addrCallback func(stun.XORMappedAddress) error
|
||||
targetHost string
|
||||
targetPort int
|
||||
}
|
||||
|
||||
func (s *NatTraversal) Cancel() {
|
||||
|
||||
close(s.cancel)
|
||||
s.conn.Close()
|
||||
}
|
||||
|
||||
func (s *NatTraversal) updateNatAddr() {
|
||||
for addr := range s.addrChan {
|
||||
if s.stunAddr == nil || s.stunAddr.String() != addr.String() { //new address
|
||||
log.Warnf("My public address: %s\n", addr)
|
||||
if s.addrCallback != nil { //execute callback
|
||||
if err := s.addrCallback(addr); err != nil {
|
||||
log.Warnf("callback error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
s.targetPort = addr.Port
|
||||
log.Infof("now proxy to target host: %s:%d", s.targetHost, s.targetPort)
|
||||
s.stunAddr = &addr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NatTraversal) sendStunServerBindingMsg() error {
|
||||
for _, srv := range getStunServers() {
|
||||
log.Debugf("send heartbeat to stun server: %s", srv)
|
||||
srvAddr, err := net.ResolveUDPAddr(udp, srv)
|
||||
if err != nil {
|
||||
log.Warnf("Failed to resolve server addr: %s", err)
|
||||
continue
|
||||
}
|
||||
err = sendBindingRequest(s.conn, srvAddr)
|
||||
if err != nil {
|
||||
log.Warnf("send binding request: %w", err)
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("failed to get STUN address")
|
||||
}
|
||||
|
||||
func (s *NatTraversal) getNatAddr(msg []byte) (*stun.XORMappedAddress, error) {
|
||||
if !stun.IsMessage(msg) {
|
||||
return nil, fmt.Errorf("not a stun message")
|
||||
}
|
||||
|
||||
m := new(stun.Message)
|
||||
m.Raw = msg
|
||||
decErr := m.Decode()
|
||||
if decErr != nil {
|
||||
return nil, fmt.Errorf("decode: %w", decErr)
|
||||
}
|
||||
var xorAddr stun.XORMappedAddress
|
||||
if getErr := xorAddr.GetFrom(m); getErr != nil {
|
||||
return nil, fmt.Errorf("getFrom: %w", getErr)
|
||||
}
|
||||
s.addrChan <- xorAddr
|
||||
|
||||
return &xorAddr, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *NatTraversal) StartProxy() {
|
||||
|
||||
tick := time.NewTicker(60 * time.Second)
|
||||
|
||||
go func() { //tcker message to check public ip and port
|
||||
defer tick.Stop()
|
||||
for {
|
||||
err := s.sendStunServerBindingMsg()
|
||||
if err != nil {
|
||||
log.Warnf("send stun server binding msg: %w", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-s.cancel:
|
||||
log.Infof("stun nat proxy cancelled")
|
||||
return
|
||||
case <-tick.C:
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.cancel:
|
||||
log.Infof("stun nat proxy cancelled")
|
||||
return
|
||||
case m := <-s.messageChan:
|
||||
if stun.IsMessage(m) {
|
||||
s.getNatAddr(m)
|
||||
} else {
|
||||
peerAddr, err := net.ResolveUDPAddr(udp, fmt.Sprintf("%s:%d", s.targetHost, s.targetPort))
|
||||
if err != nil {
|
||||
log.Errorf("resolve peeraddr: %w", err)
|
||||
continue
|
||||
}
|
||||
|
||||
send(m, s.conn, peerAddr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func listen(conn *net.UDPConn) <-chan []byte {
|
||||
messages := make(chan []byte)
|
||||
go func() {
|
||||
for {
|
||||
buf := make([]byte, 10240)
|
||||
|
||||
n, _, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
close(messages)
|
||||
|
||||
return
|
||||
}
|
||||
buf = buf[:n]
|
||||
|
||||
messages <- buf
|
||||
}
|
||||
}()
|
||||
|
||||
return messages
|
||||
}
|
||||
|
||||
func sendBindingRequest(conn *net.UDPConn, addr *net.UDPAddr) error {
|
||||
m := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
|
||||
|
||||
err := send(m.Raw, conn, addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("binding: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func send(msg []byte, conn *net.UDPConn, addr *net.UDPAddr) error {
|
||||
_, err := conn.WriteToUDP(msg, addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("send: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendStr(msg string, conn *net.UDPConn, addr *net.UDPAddr) error {
|
||||
return send([]byte(msg), conn, addr)
|
||||
}
|
||||
@@ -61,6 +61,23 @@ func (c *Client) GetAll() ([]pkg.Torrent, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetListenPort() (int, error) {
|
||||
pref, err := c.c.Preferences()
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "get preferences")
|
||||
}
|
||||
|
||||
return pref.ListenPort, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetListenPort(port int) error {
|
||||
ok, err := c.c.SetPreferences(map[string]any{"listen_port": port})
|
||||
if !ok || err != nil {
|
||||
return errors.Wrap(err, "set preferences")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Download(link, hash, dir string) (pkg.Torrent, error) {
|
||||
err := c.c.DownloadLinks([]string{link}, qbt.DownloadOptions{Savepath: &dir, Category: &c.category})
|
||||
if err != nil {
|
||||
@@ -223,7 +240,7 @@ func (t *Torrent) WalkFunc() func(fn func(path string, info fs.FileInfo) error)
|
||||
return err
|
||||
}
|
||||
}
|
||||
path, err := t.c.DefaultSavePath()
|
||||
t1, err := t.getTorrent()
|
||||
if err != nil {
|
||||
return func(fn func(path string, info fs.FileInfo) error) error {
|
||||
return err
|
||||
@@ -232,7 +249,7 @@ func (t *Torrent) WalkFunc() func(fn func(path string, info fs.FileInfo) error)
|
||||
|
||||
return func(fn func(path string, info fs.FileInfo) error) error {
|
||||
for _, file := range files {
|
||||
name := filepath.Join(path, file.Name)
|
||||
name := filepath.Join(t1.SavePath, file.Name)
|
||||
info, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -11,10 +11,17 @@ func Test1(t *testing.T) {
|
||||
log.Errorf("new client error: %v", err)
|
||||
t.Fail()
|
||||
}
|
||||
all, err := c.GetAll()
|
||||
for _, t := range all {
|
||||
name, _ := t.Name()
|
||||
log.Infof("torrent: %+v", name)
|
||||
log.Infof("new client success: %v", c)
|
||||
port, err := c.GetListenPort()
|
||||
if err != nil {
|
||||
log.Errorf("get listen port error: %v", err)
|
||||
t.Fail()
|
||||
} else {
|
||||
log.Infof("listen port: %d", port)
|
||||
err := c.SetListenPort(port + 1)
|
||||
if err!= nil {
|
||||
log.Errorf("set listen port error: %v", err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -100,11 +100,16 @@ func (b *Base) Upload(destDir string, tryLink, detectMime, changeMediaHash bool,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rel, err := filepath.Rel(b.src, path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "relation between %s and %s", b.src, path)
|
||||
}
|
||||
destName := filepath.Join(targetBase, rel)
|
||||
destName := filepath.Clean(filepath.Join(targetBase, rel))
|
||||
if !strings.HasPrefix(destName, targetBase) {
|
||||
//如果目标路径不是在目标目录下,则报错
|
||||
return errors.Errorf("destination: %s is not in target dir: %s", destName, targetBase)
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
mkdir(destName)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package tmdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"polaris/log"
|
||||
@@ -40,6 +42,21 @@ func NewClient(apiKey, proxyUrl string, enableAdultContent bool) (*Client, error
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
tmdbClient.SetClientConfig(http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 10,
|
||||
IdleConnTimeout: 15 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
if addr == "api.themoviedb.org:443" {
|
||||
addr = "18.161.6.19:443"
|
||||
}
|
||||
return net.DialTimeout(network, addr, 10*time.Second)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return &Client{
|
||||
@@ -125,7 +142,7 @@ func (c *Client) SearchMedia(query string, lang string, page int) (*SearchResult
|
||||
}
|
||||
|
||||
searchResult := &SearchResult{
|
||||
Page: res.Page,
|
||||
Page: int(res.Page),
|
||||
TotalResults: res.TotalResults,
|
||||
TotalPages: res.TotalPages,
|
||||
}
|
||||
|
||||
21
pkg/utils/dir_lib.go
Normal file
21
pkg/utils/dir_lib.go
Normal file
@@ -0,0 +1,21 @@
|
||||
//go:build lib
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
|
||||
func GetUserDataDir() string {
|
||||
d, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
d = filepath.Join(d, ".polaris")
|
||||
if _, err := os.Stat(d); os.IsNotExist(err) {
|
||||
os.MkdirAll(d, os.ModePerm)
|
||||
}
|
||||
return d
|
||||
}
|
||||
21
pkg/utils/dir_other.go
Normal file
21
pkg/utils/dir_other.go
Normal file
@@ -0,0 +1,21 @@
|
||||
//go:build !lib
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func GetUserDataDir() string {
|
||||
if IsRunningInDocker() {
|
||||
return "./data"
|
||||
}
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
dir := filepath.Join(homeDir, ".polaris")
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
os.MkdirAll(dir, 0755)
|
||||
}
|
||||
|
||||
return dir
|
||||
}
|
||||
@@ -247,7 +247,7 @@ func GetRealLinkAndHash(link string) (string, string, error) {
|
||||
if err != nil {
|
||||
return "", "", errors.Wrap(err, "parse response")
|
||||
}
|
||||
return link,info.HashInfoBytes().HexString(), nil
|
||||
return link, info.HashInfoBytes().HexString(), nil
|
||||
}
|
||||
|
||||
func Link2Magnet(link string) (string, error) {
|
||||
@@ -314,3 +314,31 @@ func DirSize(path string) (int64, error) {
|
||||
})
|
||||
return size, err
|
||||
}
|
||||
|
||||
func IsRunningInDocker() bool {
|
||||
if _, err := os.Stat("/.dockerenv"); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func UserDownloadDir() (string, error) {
|
||||
var downloadDirNames []string = []string{"Downloads", "downloads", "download", "下载"}
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, ddn := range downloadDirNames {
|
||||
var dir = filepath.Join(homeDir, ddn)
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
continue
|
||||
} else {
|
||||
return dir, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("no download dir found")
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"polaris/pkg/cache"
|
||||
"polaris/pkg/tmdb"
|
||||
"polaris/ui"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
ginzap "github.com/gin-contrib/zap"
|
||||
@@ -22,20 +24,20 @@ import (
|
||||
)
|
||||
|
||||
func NewServer(db db.Database) *Server {
|
||||
r := gin.Default()
|
||||
s := &Server{
|
||||
r: r,
|
||||
db: db,
|
||||
srv: &http.Server{},
|
||||
language: db.GetLanguage(),
|
||||
monitorNumCache: cache.NewCache[int, int](10 * time.Minute),
|
||||
downloadNumCache: cache.NewCache[int, int](10 * time.Minute),
|
||||
}
|
||||
s.core = engine.NewEngine(db, s.language)
|
||||
s.setupRoutes()
|
||||
return s
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
r *gin.Engine
|
||||
srv *http.Server
|
||||
db db.Database
|
||||
core *engine.Engine
|
||||
language string
|
||||
@@ -44,20 +46,21 @@ type Server struct {
|
||||
downloadNumCache *cache.Cache[int, int]
|
||||
}
|
||||
|
||||
func (s *Server) Serve() error {
|
||||
func (s *Server) setupRoutes() {
|
||||
s.core.Init()
|
||||
|
||||
r := gin.Default()
|
||||
s.jwtSerect = s.db.GetSetting(db.JwtSerectKey)
|
||||
//st, _ := fs.Sub(ui.Web, "build/web")
|
||||
s.r.Use(static.Serve("/", static.EmbedFolder(ui.Web, "build/web")))
|
||||
r.Use(static.Serve("/", static.EmbedFolder(ui.Web, "build/web")))
|
||||
//s.r.Use(ginzap.Ginzap(log.Logger().Desugar(), time.RFC3339, false))
|
||||
s.r.Use(ginzap.RecoveryWithZap(log.Logger().Desugar(), true))
|
||||
r.Use(ginzap.RecoveryWithZap(log.Logger().Desugar(), true))
|
||||
|
||||
log.SetLogLevel(s.db.GetSetting(db.SettingLogLevel)) //restore log level
|
||||
|
||||
s.r.POST("/api/login", HttpHandler(s.Login))
|
||||
r.POST("/api/login", HttpHandler(s.Login))
|
||||
|
||||
api := s.r.Group("/api/v1")
|
||||
api := r.Group("/api/v1")
|
||||
api.Use(s.authModdleware)
|
||||
api.StaticFS("/img", http.Dir(db.ImgPath))
|
||||
api.StaticFS("/logs", http.Dir(db.LogPath))
|
||||
@@ -98,7 +101,7 @@ func (s *Server) Serve() error {
|
||||
tv.POST("/tv/watchlist", HttpHandler(s.AddTv2Watchlist))
|
||||
tv.GET("/tv/watchlist", HttpHandler(s.GetTvWatchlist))
|
||||
tv.POST("/torrents", HttpHandler(s.SearchAvailableTorrents))
|
||||
tv.POST("/torrents/download/", HttpHandler(s.DownloadTorrent))
|
||||
tv.POST("/torrents/download", HttpHandler(s.DownloadTorrent))
|
||||
tv.POST("/movie/watchlist", HttpHandler(s.AddMovie2Watchlist))
|
||||
tv.GET("/movie/watchlist", HttpHandler(s.GetMovieWatchlist))
|
||||
tv.GET("/record/:id", HttpHandler(s.GetMediaDetails))
|
||||
@@ -142,9 +145,40 @@ func (s *Server) Serve() error {
|
||||
importlist.POST("/add", HttpHandler(s.addImportlist))
|
||||
importlist.DELETE("/delete", HttpHandler(s.deleteImportList))
|
||||
}
|
||||
log.Infof("----------- Polaris Server Successfully Started ------------")
|
||||
s.srv.Handler = r
|
||||
|
||||
return s.r.Run(":8080")
|
||||
}
|
||||
|
||||
func (s *Server) Start(addr string) (int, error) {
|
||||
if addr == "" {
|
||||
addr = "127.0.0.1:0" // 0 means any available port
|
||||
}
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to listen on port: %w", err)
|
||||
}
|
||||
|
||||
_, port, _ := net.SplitHostPort(ln.Addr().String())
|
||||
|
||||
p, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to convert port to int: %w", err)
|
||||
}
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
if err := s.srv.Serve(ln); err != nil {
|
||||
log.Errorf("failed to serve: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Infof("----------- Polaris Server Successfully Started on Port %d------------", p)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
log.Infof("Stopping Polaris Server...")
|
||||
return s.srv.Close()
|
||||
}
|
||||
|
||||
func (s *Server) TMDB() (*tmdb.Client, error) {
|
||||
|
||||
@@ -190,12 +190,13 @@ func (s *Server) GetAllIndexers(c *gin.Context) (interface{}, error) {
|
||||
}
|
||||
|
||||
type downloadClientIn struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
URL string `json:"url" binding:"required"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Implementation string `json:"implementation" binding:"required"`
|
||||
Priority int `json:"priority"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
URL string `json:"url" binding:"required"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
Implementation string `json:"implementation" binding:"required"`
|
||||
Priority int `json:"priority"`
|
||||
UseNatTraversal bool `json:"use_nat_traversal"`
|
||||
}
|
||||
|
||||
func (s *Server) AddDownloadClient(c *gin.Context) (interface{}, error) {
|
||||
@@ -225,15 +226,17 @@ func (s *Server) AddDownloadClient(c *gin.Context) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
if err := s.db.SaveDownloader(&ent.DownloadClients{
|
||||
Name: in.Name,
|
||||
Implementation: downloadclients.Implementation(in.Implementation),
|
||||
Priority1: in.Priority,
|
||||
URL: in.URL,
|
||||
User: in.User,
|
||||
Password: in.Password,
|
||||
Name: in.Name,
|
||||
Implementation: downloadclients.Implementation(in.Implementation),
|
||||
Priority1: in.Priority,
|
||||
URL: in.URL,
|
||||
User: in.User,
|
||||
Password: in.Password,
|
||||
UseNatTraversal: in.UseNatTraversal,
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "save downloader")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"polaris/db"
|
||||
"strings"
|
||||
|
||||
"polaris/log"
|
||||
"polaris/pkg/alist"
|
||||
@@ -52,10 +53,17 @@ func (s *Server) AddStorage(c *gin.Context) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasSuffix(in.TvPath, string(os.PathSeparator)) {
|
||||
in.TvPath = in.TvPath + string(os.PathSeparator)
|
||||
}
|
||||
_, err = os.Stat(in.MoviePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !strings.HasSuffix(in.MoviePath, string(os.PathSeparator)) {
|
||||
in.MoviePath = in.MoviePath + string(os.PathSeparator)
|
||||
}
|
||||
|
||||
}
|
||||
log.Infof("received add storage input: %v", in)
|
||||
err := s.db.AddStorage(&in)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !c
|
||||
//go:build !lib
|
||||
package ui
|
||||
|
||||
import "embed"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build c
|
||||
//go:build lib
|
||||
package ui
|
||||
|
||||
import "embed"
|
||||
|
||||
17
ui/lib/ffi/entry/libpolaris_boot_browser.dart
Normal file
17
ui/lib/ffi/entry/libpolaris_boot_browser.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:ui/ffi/lib_polaris_boot.dart';
|
||||
|
||||
LibPolarisBoot create() {
|
||||
return LibpolarisBootBrowser();
|
||||
}
|
||||
|
||||
class LibpolarisBootBrowser implements LibPolarisBoot {
|
||||
@override
|
||||
Future<int> start(String cfg) async{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stop() async{
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,14 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:quiver/strings.dart';
|
||||
import 'package:ui/ffi/lib_polaris_boot.dart';
|
||||
|
||||
LibPolarisBoot create() => LibpolarisBootNative();
|
||||
|
||||
class FFIBackend {
|
||||
class LibpolarisBootNative implements LibPolarisBoot {
|
||||
final lib = DynamicLibrary.open(libname());
|
||||
|
||||
static String libname() {
|
||||
@@ -25,17 +28,31 @@ class FFIBackend {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> start() async {
|
||||
@override
|
||||
Future<int> start(String cfg) async {
|
||||
var s = lib
|
||||
.lookup<NativeFunction<Void Function()>>('Start')
|
||||
.asFunction<void Function()>();
|
||||
|
||||
return Isolate.run(s);
|
||||
.lookupFunction<StartFunc, StartFunc>('Start')
|
||||
;
|
||||
var r = s(cfg.toNativeUtf8());
|
||||
if (isNotBlank(r.r1.toDartString())) {
|
||||
throw Exception(r.r1.toDartString());
|
||||
}
|
||||
return r.r0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> stop() async {
|
||||
var s = lib
|
||||
var s = lib
|
||||
.lookup<NativeFunction<Void Function()>>('Stop')
|
||||
.asFunction<void Function()>();
|
||||
return s();
|
||||
}
|
||||
}
|
||||
|
||||
typedef StartFunc = StartReturn Function(Pointer<Utf8> cfg);
|
||||
|
||||
final class StartReturn extends Struct {
|
||||
@Int32()
|
||||
external int r0;
|
||||
external Pointer<Utf8> r1;
|
||||
}
|
||||
18
ui/lib/ffi/lib_polaris_boot.dart
Normal file
18
ui/lib/ffi/lib_polaris_boot.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:ui/ffi/lib_polaris_boot_stub.dart'
|
||||
if (dart.library.html) 'package:ui/ffi/entry/libpolaris_boot_browser.dart'
|
||||
if (dart.library.io) 'package:ui/ffi/entry/libpolaris_boot_native.dart';
|
||||
|
||||
abstract class LibPolarisBoot {
|
||||
static LibPolarisBoot? _instance;
|
||||
|
||||
static LibPolarisBoot get instance {
|
||||
_instance ??= LibPolarisBoot();
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
factory LibPolarisBoot() => create();
|
||||
|
||||
Future<int> start(String cfg);
|
||||
|
||||
Future<void> stop();
|
||||
}
|
||||
5
ui/lib/ffi/lib_polaris_boot_stub.dart
Normal file
5
ui/lib/ffi/lib_polaris_boot_stub.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
import 'package:ui/ffi/lib_polaris_boot.dart';
|
||||
|
||||
LibPolarisBoot create() => throw UnimplementedError();
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:ui/activity.dart';
|
||||
import 'package:ui/ffi/lib_polaris_boot.dart';
|
||||
import 'package:ui/init_wizard.dart';
|
||||
import 'package:ui/login_page.dart';
|
||||
import 'package:ui/movie_watchlist.dart';
|
||||
@@ -16,9 +18,10 @@ import 'package:ui/welcome_page.dart';
|
||||
import 'package:ui/widgets/utils.dart';
|
||||
|
||||
void main() async {
|
||||
// if (isDesktop()) {
|
||||
// FFIBackend().start();
|
||||
// }
|
||||
if (!kIsWeb) {
|
||||
var port = await LibPolarisBoot.instance.start("");
|
||||
APIs.port = port;
|
||||
}
|
||||
|
||||
initializeDateFormatting()
|
||||
.then((_) => runApp(const ProviderScope(child: MyApp())));
|
||||
|
||||
@@ -5,9 +5,9 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ui/providers/server_response.dart';
|
||||
import 'package:ui/widgets/utils.dart';
|
||||
|
||||
class APIs {
|
||||
static int port = 8096;
|
||||
static final _baseUrl = baseUrl();
|
||||
static final searchUrl = "$_baseUrl/api/v1/media/search";
|
||||
static final editMediaUrl = "$_baseUrl/api/v1/media/edit";
|
||||
@@ -19,7 +19,7 @@ class APIs {
|
||||
//static final singleSettingUrl = "$_baseUrl/api/v1/setting/";
|
||||
static final watchlistTvUrl = "$_baseUrl/api/v1/media/tv/watchlist";
|
||||
static final watchlistMovieUrl = "$_baseUrl/api/v1/media/movie/watchlist";
|
||||
static final availableTorrentsUrl = "$_baseUrl/api/v1/media/torrents/";
|
||||
static final availableTorrentsUrl = "$_baseUrl/api/v1/media/torrents";
|
||||
static final downloadTorrentUrl = "$_baseUrl/api/v1/media/torrents/download";
|
||||
static final seriesDetailUrl = "$_baseUrl/api/v1/media/record/";
|
||||
static final suggestedTvName = "$_baseUrl/api/v1/media/suggest/tv/";
|
||||
@@ -31,7 +31,7 @@ class APIs {
|
||||
static final allDownloadClientsUrl = "$_baseUrl/api/v1/downloader";
|
||||
static final addDownloadClientUrl = "$_baseUrl/api/v1/downloader/add";
|
||||
static final delDownloadClientUrl = "$_baseUrl/api/v1/downloader/del/";
|
||||
static final storageUrl = "$_baseUrl/api/v1/storage/";
|
||||
static final storageUrl = "$_baseUrl/api/v1/storage";
|
||||
static final loginUrl = "$_baseUrl/api/login";
|
||||
static final logoutUrl = "$_baseUrl/api/v1/setting/logout";
|
||||
static final loginSettingUrl = "$_baseUrl/api/v1/setting/auth";
|
||||
@@ -45,12 +45,12 @@ class APIs {
|
||||
static final changeMonitoringUrl = "$_baseUrl/api/v1/setting/monitoring";
|
||||
static final addImportlistUrl = "$_baseUrl/api/v1/importlist/add";
|
||||
static final deleteImportlistUrl = "$_baseUrl/api/v1/importlist/delete";
|
||||
static final getAllImportlists = "$_baseUrl/api/v1/importlist/";
|
||||
static final getAllImportlists = "$_baseUrl/api/v1/importlist";
|
||||
static final prowlarrUrl = "$_baseUrl/api/v1/setting/prowlarr";
|
||||
|
||||
static final notifierAllUrl = "$_baseUrl/api/v1/notifier/all";
|
||||
static final notifierDeleteUrl = "$_baseUrl/api/v1/notifier/id/";
|
||||
static final notifierAddUrl = "$_baseUrl/api/v1/notifier/add/";
|
||||
static final notifierAddUrl = "$_baseUrl/api/v1/notifier/add";
|
||||
|
||||
static final tmdbImgBaseUrl = "$_baseUrl/api/v1/posters";
|
||||
|
||||
@@ -63,7 +63,6 @@ class APIs {
|
||||
|
||||
static final blacklistUrl = "$_baseUrl/api/v1/activity/blacklist";
|
||||
|
||||
|
||||
static const tmdbApiKey = "tmdb_api_key";
|
||||
static const downloadDirKey = "download_dir";
|
||||
|
||||
@@ -71,10 +70,11 @@ class APIs {
|
||||
GlobalKey<NavigatorState>();
|
||||
|
||||
static String baseUrl() {
|
||||
if (!kIsWeb) {
|
||||
return "http://127.0.0.1:$port";
|
||||
}
|
||||
|
||||
if (kReleaseMode) {
|
||||
if (!kIsWeb) {
|
||||
return "http://127.0.0.1:8080";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
return "http://127.0.0.1:8080";
|
||||
@@ -82,15 +82,23 @@ class APIs {
|
||||
|
||||
static Dio getDio() {
|
||||
var dio = Dio();
|
||||
dio.options.followRedirects = true;
|
||||
dio.interceptors.add(InterceptorsWrapper(
|
||||
onError: (error, handler) {
|
||||
onError: (error, handler) async {
|
||||
if (error.response?.statusCode != null &&
|
||||
error.response?.statusCode! == 403) {
|
||||
//not login
|
||||
final context = navigatorKey.currentContext;
|
||||
if (context != null) {
|
||||
context.go('/login');
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response?.statusCode == 307) {
|
||||
final redirectUrl = error.response!.headers['Location']!.first;
|
||||
final newResponse = await dio.get(_baseUrl+redirectUrl);
|
||||
return handler.resolve(newResponse); // 返回修正后的响应
|
||||
}
|
||||
return handler.next(error);
|
||||
},
|
||||
));
|
||||
|
||||
@@ -7,7 +7,9 @@ import 'package:ui/providers/server_response.dart';
|
||||
var activitiesDataProvider = AsyncNotifierProvider.autoDispose
|
||||
.family<ActivityData, List<Activity>, ActivityStatus>(ActivityData.new);
|
||||
|
||||
var blacklistDataProvider = AsyncNotifierProvider.autoDispose<BlacklistData,List<Blacklist>>(BlacklistData.new);
|
||||
var blacklistDataProvider =
|
||||
AsyncNotifierProvider.autoDispose<BlacklistData, List<Blacklist>>(
|
||||
BlacklistData.new);
|
||||
|
||||
var mediaHistoryDataProvider = FutureProvider.autoDispose.family(
|
||||
(ref, arg) async {
|
||||
@@ -84,7 +86,6 @@ class ActivityData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Activity {
|
||||
Activity(
|
||||
{required this.id,
|
||||
@@ -110,8 +111,8 @@ class Activity {
|
||||
final String? saved;
|
||||
final int? progress;
|
||||
final int? size;
|
||||
final double? seedRatio;
|
||||
final double? uploadProgress;
|
||||
final num? seedRatio;
|
||||
final num? uploadProgress;
|
||||
|
||||
factory Activity.fromJson(Map<String, dynamic> json) {
|
||||
return Activity(
|
||||
@@ -123,22 +124,21 @@ class Activity {
|
||||
targetDir: json["target_dir"],
|
||||
status: json["status"],
|
||||
saved: json["saved"],
|
||||
progress: json["progress"]??0,
|
||||
seedRatio: json["seed_ratio"]??0,
|
||||
size: json["size"]??0,
|
||||
uploadProgress: json["upload_progress"]??0);
|
||||
progress: json["progress"] ?? 0,
|
||||
seedRatio: json["seed_ratio"] ?? 0,
|
||||
size: json["size"] ?? 0,
|
||||
uploadProgress: json["upload_progress"] ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BlacklistData extends AutoDisposeAsyncNotifier<List<Blacklist>> {
|
||||
@override
|
||||
FutureOr<List<Blacklist>> build() async {
|
||||
final dio = APIs.getDio();
|
||||
var resp = await dio.get(APIs.blacklistUrl);
|
||||
final sp = ServerResponse.fromJson(resp.data);
|
||||
if (sp.code!= 0) {
|
||||
throw sp.message;
|
||||
final sp = ServerResponse.fromJson(resp.data);
|
||||
if (sp.code != 0) {
|
||||
throw sp.message;
|
||||
}
|
||||
List<Blacklist> blaclklists = List.empty(growable: true);
|
||||
for (final a in sp.data as List) {
|
||||
@@ -151,7 +151,7 @@ class BlacklistData extends AutoDisposeAsyncNotifier<List<Blacklist>> {
|
||||
final dio = APIs.getDio();
|
||||
var resp = await dio.delete("${APIs.blacklistUrl}/$id");
|
||||
final sp = ServerResponse.fromJson(resp.data);
|
||||
if (sp.code!= 0) {
|
||||
if (sp.code != 0) {
|
||||
throw sp.message;
|
||||
}
|
||||
}
|
||||
@@ -192,4 +192,4 @@ class Blacklist {
|
||||
data['create_time'] = this.createTime;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,10 @@ class SeriesDetailData
|
||||
return SeriesDetails.fromJson(rsp.data);
|
||||
}
|
||||
|
||||
Future<void> delete(bool removeFiles ) async {
|
||||
Future<void> delete(bool removeFiles) async {
|
||||
final dio = APIs.getDio();
|
||||
var resp = await dio.delete("${APIs.seriesDetailUrl}$id", queryParameters: {"delete_files": removeFiles});
|
||||
var resp = await dio.delete("${APIs.seriesDetailUrl}$id",
|
||||
queryParameters: {"delete_files": removeFiles});
|
||||
var rsp = ServerResponse.fromJson(resp.data);
|
||||
if (rsp.code != 0) {
|
||||
throw rsp.message;
|
||||
@@ -250,12 +251,13 @@ class MediaTorrentResource extends AutoDisposeFamilyAsyncNotifier<
|
||||
"season": arg.seasonNumber,
|
||||
"episode": arg.episodeNumber
|
||||
});
|
||||
final dio = await APIs.getDio();
|
||||
final dio = APIs.getDio();
|
||||
var resp = await dio.post(APIs.downloadTorrentUrl, data: data);
|
||||
var rsp = ServerResponse.fromJson(resp.data);
|
||||
if (rsp.code != 0) {
|
||||
throw rsp.message;
|
||||
}
|
||||
ref.invalidate(mediaDetailsProvider(arg.mediaId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,8 +281,8 @@ class TorrentResource {
|
||||
String? link;
|
||||
String? source;
|
||||
int? indexerId;
|
||||
double? downloadFactor;
|
||||
double? uploadFactor;
|
||||
num? downloadFactor;
|
||||
num? uploadFactor;
|
||||
bool? isPrivate;
|
||||
|
||||
factory TorrentResource.fromJson(Map<String, dynamic> json) {
|
||||
|
||||
@@ -251,6 +251,7 @@ class DownloadClient {
|
||||
bool? removeCompletedDownloads;
|
||||
bool? removeFailedDownloads;
|
||||
int? priority;
|
||||
bool useNatTraversal = false;
|
||||
DownloadClient(
|
||||
{this.id,
|
||||
this.enable,
|
||||
@@ -261,7 +262,7 @@ class DownloadClient {
|
||||
this.password,
|
||||
this.removeCompletedDownloads = true,
|
||||
this.priority = 1,
|
||||
this.removeFailedDownloads = true});
|
||||
this.removeFailedDownloads = true, this.useNatTraversal = false});
|
||||
|
||||
DownloadClient.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
@@ -274,6 +275,7 @@ class DownloadClient {
|
||||
priority = json["priority1"];
|
||||
removeCompletedDownloads = json["remove_completed_downloads"] ?? false;
|
||||
removeFailedDownloads = json["remove_failed_downloads"] ?? false;
|
||||
useNatTraversal = json["use_nat_traversal"]?? false;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
@@ -288,6 +290,7 @@ class DownloadClient {
|
||||
data["priority"] = priority;
|
||||
data["remove_completed_downloads"] = removeCompletedDownloads;
|
||||
data["remove_failed_downloads"] = removeFailedDownloads;
|
||||
data["use_nat_traversal"] = useNatTraversal;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -315,7 +318,7 @@ class StorageSettingData extends AutoDisposeAsyncNotifier<List<Storage>> {
|
||||
|
||||
Future<void> deleteStorage(int id) async {
|
||||
final dio = await APIs.getDio();
|
||||
var resp = await dio.delete("${APIs.storageUrl}$id");
|
||||
var resp = await dio.delete("${APIs.storageUrl}/$id");
|
||||
var sp = ServerResponse.fromJson(resp.data);
|
||||
if (sp.code != 0) {
|
||||
throw sp.message;
|
||||
|
||||
@@ -63,6 +63,7 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
||||
"remove_completed_downloads": client.removeCompletedDownloads,
|
||||
"remove_failed_downloads": client.removeFailedDownloads,
|
||||
"priority": client.priority.toString(),
|
||||
"use_nat_traversal": client.useNatTraversal,
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -86,6 +87,12 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
||||
labelText: "优先级", helperText: "1-50, 1最高优先级,50最低优先级"),
|
||||
validator: FormBuilderValidators.integer(),
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction),
|
||||
// FormBuilderSwitch(
|
||||
// name: "use_nat_traversal",
|
||||
// enabled: client.implementation == "qbittorrent",
|
||||
// title: const Text("使用内置STUN NAT穿透"),
|
||||
// decoration: InputDecoration(helperText: "内建的NAT穿透功能帮助BT客户端上传(会自动更改下载器的监听地址)"),
|
||||
// ),
|
||||
FormBuilderSwitch(
|
||||
name: "remove_completed_downloads",
|
||||
title: const Text("任务完成后删除")),
|
||||
@@ -150,6 +157,7 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
||||
user: _enableAuth ? values["user"] : null,
|
||||
password: _enableAuth ? values["password"] : null,
|
||||
priority: int.parse(values["priority"]),
|
||||
useNatTraversal: values["use_nat_traversal"],
|
||||
removeCompletedDownloads: values["remove_completed_downloads"],
|
||||
removeFailedDownloads: values["remove_failed_downloads"]));
|
||||
} else {
|
||||
@@ -165,7 +173,12 @@ class _DownloaderState extends ConsumerState<DownloaderSettings> {
|
||||
}
|
||||
|
||||
return showSettingDialog(
|
||||
context, title, client.idExists() && client.implementation != "buildin", body, onSubmit, onDelete);
|
||||
context,
|
||||
title,
|
||||
client.idExists() && client.implementation != "buildin",
|
||||
body,
|
||||
onSubmit,
|
||||
onDelete);
|
||||
}
|
||||
|
||||
Future<void> showSelections() {
|
||||
|
||||
@@ -93,7 +93,7 @@ class _SystemPageState extends ConsumerState<SystemPage> {
|
||||
]),
|
||||
DataRow(cells: [
|
||||
const DataCell(Text("更新监控列表")),
|
||||
const DataCell(Text("每小时")),
|
||||
const DataCell(Text("每20分钟")),
|
||||
DataCell(IconButton(
|
||||
icon: const Icon(Icons.not_started),
|
||||
onPressed: () =>
|
||||
|
||||
@@ -21,10 +21,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.12.0"
|
||||
version: "2.13.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -93,10 +93,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -122,18 +122,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_form_builder
|
||||
sha256: "375da52998c72f80dec9187bd93afa7ab202b89d5d066699368ff96d39fd4876"
|
||||
sha256: aa3901466c70b69ae6c7f3d03fcbccaec5fde179d3fded0b10203144b546ad28
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "9.7.0"
|
||||
version: "10.0.1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
||||
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
version: "6.0.0"
|
||||
flutter_localizations:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -185,10 +185,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3
|
||||
sha256: "0b1e06223bee260dee31a171fb1153e306907563a0b0225e8c1733211911429a"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "14.8.1"
|
||||
version: "15.1.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -201,10 +201,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
version: "0.20.2"
|
||||
intl_phone_number_input:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -225,10 +225,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "10.0.8"
|
||||
version: "10.0.9"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -273,10 +273,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
version: "6.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -430,10 +430,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: table_calendar
|
||||
sha256: b2896b7c86adf3a4d9c911d860120fe3dbe03c85db43b22fd61f14ee78cdbb63
|
||||
sha256: "0c0c6219878b363a2d5f40c7afb159d845f253d061dc3c822aa0d5fe0f721982"
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
version: "3.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -454,10 +454,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: timeago
|
||||
sha256: "054cedf68706bb142839ba0ae6b135f6b68039f0b8301cbe8784ae653d5ff8de"
|
||||
sha256: b05159406a97e1cbb2b9ee4faa9fb096fe0e2dfcd8b08fcd2a00553450d3422e
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "3.7.0"
|
||||
version: "3.7.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -542,10 +542,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "14.3.1"
|
||||
version: "15.0.0"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -555,5 +555,5 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
sdks:
|
||||
dart: ">=3.7.0 <4.0.0"
|
||||
flutter: ">=3.27.0"
|
||||
dart: ">=3.8.0 <4.0.0"
|
||||
flutter: ">=3.29.0"
|
||||
|
||||
@@ -37,13 +37,13 @@ dependencies:
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
go_router: ^14.3.0
|
||||
go_router: ^15.1.2
|
||||
flutter_riverpod: ^2.6.1
|
||||
quiver: ^3.2.2
|
||||
flutter_login: ^5.0.0
|
||||
intl: ^0.19.0
|
||||
intl: ^0.20.2
|
||||
flutter_adaptive_scaffold: ^0.3.1
|
||||
flutter_form_builder: ^9.5.0
|
||||
flutter_form_builder: ^10.0.1
|
||||
form_builder_validators: ^11.0.0
|
||||
url_launcher: ^6.3.1
|
||||
timeago: ^3.7.0
|
||||
@@ -58,7 +58,7 @@ dev_dependencies:
|
||||
# activated in the `analysis_options.yaml` file located at the root of your
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^5.0.0
|
||||
flutter_lints: ^6.0.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
@@ -4,7 +4,7 @@ project(ui LANGUAGES CXX)
|
||||
|
||||
# The name of the executable created for the application. Change this to change
|
||||
# the on-disk name of your application.
|
||||
set(BINARY_NAME "ui")
|
||||
set(BINARY_NAME "polaris")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
|
||||
@@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
|
||||
FlutterWindow window(project);
|
||||
Win32Window::Point origin(10, 10);
|
||||
Win32Window::Size size(1280, 720);
|
||||
if (!window.Create(L"ui", origin, size)) {
|
||||
if (!window.Create(L"Polaris", origin, size)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
window.SetQuitOnClose(true);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 43 KiB |
Reference in New Issue
Block a user