diff --git a/.github/workflows/buildgo.yml b/.github/workflows/buildgo.yml
new file mode 100644
index 00000000..4d3703d6
--- /dev/null
+++ b/.github/workflows/buildgo.yml
@@ -0,0 +1,160 @@
+name: Build Go
+
+on:
+ # push:
+ # branches:
+ # - cn
+ # pull_request:
+ # branches:
+ # - cn
+ workflow_dispatch:
+ inputs:
+ reason:
+ description: '运行原因'
+ required: false
+ default: '手动触发构建'
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref_name }}
+ cancel-in-progress: true
+jobs:
+
+ build-for-linux:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.22
+ - name: Build
+ run: |
+ cd go
+ go build -buildmode=c-shared -ldflags="-s -w" -trimpath -o libmtorrentserver.so ./binding/desktop
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: libmtorrentserver-linux
+ path: go/libmtorrentserver.*
+
+ build-for-macos:
+ runs-on: macos-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.22
+ - name: Build for ARM64
+ run: |
+ cd go
+ CGO_ENABLED=1 GOARCH=arm64 go build -buildmode=c-shared -ldflags="-s -w" -trimpath -o libmtorrentserver_arm64.dylib ./binding/desktop
+ - name: Build for AMD64
+ run: |
+ cd go
+ CGO_ENABLED=1 GOARCH=amd64 go build -buildmode=c-shared -ldflags="-s -w" -trimpath -o libmtorrentserver_amd64.dylib ./binding/desktop
+ - name: Create Universal Binary
+ run: |
+ cd go
+ lipo -create -output libmtorrentserver.dylib libmtorrentserver_arm64.dylib libmtorrentserver_amd64.dylib
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: libmtorrentserver-macos
+ path: go/libmtorrentserver*
+
+ build-for-windows:
+ runs-on: windows-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.22
+
+ - name: Build for Windows (64-bit)
+ run: |
+ cd go
+ $env:CGO_ENABLED = "1"
+ $env:CC = "gcc"
+ $env:GOARCH = "amd64"
+ go build -buildmode=c-shared -ldflags="-s -w -extldflags=-Wl,--allow-multiple-definition" -trimpath -o libmtorrentserver.dll ./binding/desktop
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: libmtorrentserver-windows-64bit
+ path: go/libmtorrentserver.*
+
+ build-for-android:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.22
+ - name: Setup Java toolchain
+ uses: actions/setup-java@v4
+ with:
+ distribution: "temurin"
+ java-version: "17"
+ - name: Setup Android SDK
+ uses: android-actions/setup-android@v3
+ - name: Setup Android SDK and NDK
+ run: |
+ sdkmanager --install "ndk;25.2.9519653"
+ echo "ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk/25.2.9519653" >> $GITHUB_ENV
+ - name: Install gomobile
+ run: |
+ go install golang.org/x/mobile/cmd/gomobile@latest
+ go install golang.org/x/mobile/cmd/gobind@latest
+ - name: Initialize gomobile
+ run: |
+ export PATH=$PATH:$(go env GOPATH)/bin
+ gomobile init -v
+ - name: Build Android AAR
+ run: |
+ cd go
+ go get -u golang.org/x/mobile
+ gomobile bind -v -target=android/arm,android/arm64,android/amd64,android/386 -androidapi 21 -ldflags="-s -w" -trimpath -o libmtorrentserver.aar ./binding/mobile
+ - name: Upload Android Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ name: libmtorrentserver-android
+ path: go/libmtorrentserver.aar
+
+ build-for-iOS:
+ runs-on: macos-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.22
+ - name: Set up Xcode
+ uses: maxim-lobanov/setup-xcode@v1
+ with:
+ xcode-version: latest-stable
+ - name: Install gomobile
+ run: |
+ go install golang.org/x/mobile/cmd/gomobile@latest
+ go install golang.org/x/mobile/cmd/gobind@latest
+ - name: Initialize gomobile
+ run: |
+ gomobile init -v
+ - name: Build for iOS
+ run: |
+ cd go
+ go get -u golang.org/x/mobile
+ gomobile bind -target=ios,iossimulator -ldflags="-s -w" -trimpath -o libmtorrentserver.xcframework ./binding/mobile
+ - name: Upload iOS Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: libmtorrentserver-ios
+ path: go/libmtorrentserver.xcframework
diff --git a/android/app/libs/libmtorrentserver.aar b/android/app/libs/libmtorrentserver.aar
index 6be09bbf..a4ab8ae8 100644
Binary files a/android/app/libs/libmtorrentserver.aar and b/android/app/libs/libmtorrentserver.aar differ
diff --git a/go/go.mod b/go/go.mod
index 677ce60a..3f1d3e82 100644
--- a/go/go.mod
+++ b/go/go.mod
@@ -4,6 +4,9 @@ go 1.22
require (
github.com/anacrolix/torrent v1.56.1
+ github.com/bzsome/chaoGo v0.0.0-20200507035022-6877566c86c4
+ github.com/go-resty/resty/v2 v2.15.3
+ github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/rs/cors v1.11.1
)
@@ -84,6 +87,7 @@ require (
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/time v0.6.0 // indirect
+ gopkg.in/eapache/queue.v1 v1.1.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
modernc.org/libc v1.60.1 // indirect
diff --git a/go/go.sum b/go/go.sum
index 6c41e56b..c1fa7185 100644
--- a/go/go.sum
+++ b/go/go.sum
@@ -97,6 +97,8 @@ github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2w
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og=
+github.com/bzsome/chaoGo v0.0.0-20200507035022-6877566c86c4 h1:l6wSeJg2s2Zb9skY0nieOfUBjhsap4wBCs4I9Mg/j4U=
+github.com/bzsome/chaoGo v0.0.0-20200507035022-6877566c86c4/go.mod h1:wAevNZnFg5znj0ZcO+FqyNE1Qr2Go4isYoTpUyIgXag=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -139,6 +141,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8=
+github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -179,8 +183,6 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/gortc/stun v1.20.0 h1:7FNyWwjRXVByBItBwpnsv6SZ08UzPfmByLjKmOnpb14=
-github.com/gortc/stun v1.20.0/go.mod h1:/XeODKxk0b1P5pYtdD/ZlOncR7+6XgU4zb9CzJIFJBs=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
@@ -235,6 +237,8 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
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/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
+github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
+github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
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=
@@ -266,8 +270,6 @@ github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk=
github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
-github.com/pion/stun v1.17.3 h1:JioTPckDp7PdfoF1FYSz1/sOWrXimbjyfZzvg2QIinU=
-github.com/pion/stun v1.17.3/go.mod h1:4iy9kiYvpncdXoYYJoAvZ4YFybb4/gQmZxUNaU2680Y=
github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA=
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
@@ -507,6 +509,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/eapache/queue.v1 v1.1.0 h1:EldqoJEGtXYiVCMRo2C9mePO2UUGnYn2+qLmlQSqPdc=
+gopkg.in/eapache/queue.v1 v1.1.0/go.mod h1:wNtmx1/O7kZSR9zNT1TTOJ7GLpm3Vn7srzlfylFbQwU=
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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
diff --git a/go/server.go b/go/server.go
index e72378da..8d409670 100644
--- a/go/server.go
+++ b/go/server.go
@@ -2,28 +2,60 @@ package server
//credits: https://github.com/glblduh/StreamRest
import (
+ "bufio"
+ "bytes"
"context"
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/base64"
"encoding/json"
+ "fmt"
+ "io"
"log"
"net"
"net/http"
+ "net/http/cookiejar"
"net/url"
"os"
"os/signal"
"path/filepath"
+ "regexp"
+ "runtime"
+ "strconv"
"strings"
+ "sync"
"syscall"
"time"
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo"
"github.com/rs/cors"
+
+ "github.com/bzsome/chaoGo/workpool"
+ "github.com/go-resty/resty/v2"
+ "github.com/patrickmn/go-cache"
)
var torrentCli *torrent.Client
var torrentcliCfg *torrent.ClientConfig
func Start(config *Config) (int, error) {
+ signal.Ignore(syscall.SIGPIPE)
+ // Set log output
+ log.SetOutput(os.Stdout)
+
+ // Set log prefix and flags
+ log.SetPrefix("[MediaServer] ")
+ log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
+
+ // DnsResolverIP = "8.8.8.8:53"
+
+ InitClient()
+
+ if isWorkPool == nil {
+ isWorkPool = new(bool)
+ }
+ *isWorkPool = true
torrentcliCfg = torrent.NewDefaultClientConfig()
@@ -62,7 +94,7 @@ func Start(config *Config) (int, error) {
mux.HandleFunc("/torrent/torrents", listTorrents)
mux.HandleFunc("/torrent/play", playTorrent)
mux.HandleFunc("/torrent/add", AddTorrent)
- mux.HandleFunc("/", Init)
+ mux.HandleFunc("/", handleMethod)
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
@@ -529,3 +561,981 @@ type Config struct {
Address string `json:"address"`
Path string `json:"path"`
}
+
+type Emitter struct {
+ pipeReader *io.PipeReader
+ pipeWriter *io.PipeWriter
+ closed bool
+}
+
+func (em *Emitter) IsClosed() bool {
+ return em.closed
+}
+
+func (em *Emitter) Read(b []byte) (int, error) {
+ n, err := em.pipeReader.Read(b)
+ if err != nil {
+ em.Close()
+ return 0, err
+ }
+ return n, nil
+}
+
+func (em *Emitter) Write(b []byte) (int, error) {
+ n, err := em.pipeWriter.Write(b)
+ if err != nil {
+ em.Close()
+ return 0, err
+ }
+ return n, nil
+}
+
+func (em *Emitter) WriteString(s string) (int, error) {
+ return em.Write([]byte(s))
+}
+
+func (em *Emitter) Close() error {
+ em.closed = true
+ em.pipeReader.Close()
+ em.pipeWriter.Close()
+ return nil
+}
+
+func NewEmitter(reader *io.PipeReader, writer *io.PipeWriter) *Emitter {
+ return &Emitter{
+ pipeReader: reader,
+ pipeWriter: writer,
+ closed: false,
+ }
+}
+
+var (
+ NoRedirectClient *resty.Client
+ NoRedirectClientWithProxy *resty.Client
+ RestyClient *resty.Client
+ RestyClientWithProxy *resty.Client
+ HttpClient *http.Client
+ // DnsResolverIP string // Initialize to empty string
+ IdleConnTimeout = 10 * time.Second
+ // dnsResolverProto = "udp"
+ // dnsResolverTimeoutMs = 10000
+)
+var UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
+var DefaultTimeout = time.Second * 30
+
+func InitClient() {
+ NoRedirectClient = resty.New().SetRedirectPolicy(
+ resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ }),
+ ).SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
+ NoRedirectClient.SetHeader("user-agent", UserAgent)
+
+ NoRedirectClientWithProxy = resty.New().SetRedirectPolicy(
+ resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ }),
+ )
+ NoRedirectClientWithProxy.SetHeader("user-agent", UserAgent)
+ RestyClient = NewRestyClient()
+ RestyClientWithProxy = NewRestyClient()
+ HttpClient = NewHttpClient()
+}
+
+func NewRestyClient() *resty.Client {
+ // dialer := &net.Dialer{
+ // // Timeout: ConnectTimeout * time.Second, // 设置连接超时为
+ // Resolver: &net.Resolver{
+ // PreferGo: true,
+ // Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
+ // d := net.Dialer{
+ // Timeout: time.Duration(dnsResolverTimeoutMs) * time.Millisecond,
+ // }
+ // return d.DialContext(ctx, dnsResolverProto, DnsResolverIP)
+ // },
+ // },
+ // }
+
+ transport := &http.Transport{
+ // DialContext: dialer.DialContext,
+ TLSClientConfig: &tls.Config{
+ InsecureSkipVerify: true,
+ VerifyPeerCertificate: func(certificates [][]byte, _ [][]*x509.Certificate) error {
+ // Completely ignore certificate verification 完全忽略证书验证
+ return nil
+ },
+ },
+ IdleConnTimeout: IdleConnTimeout,
+ }
+
+ client := resty.New().
+ SetHeader("user-agent", UserAgent).
+ SetRetryCount(3).
+ SetTimeout(DefaultTimeout).
+ SetTransport(transport)
+ return client
+}
+
+func NewHttpClient() *http.Client {
+ // dialer := &net.Dialer{
+ // //Timeout: 30 * time.Second,
+ // // Timeout: ConnectTimeout, // 设置连接超时为
+ // Resolver: &net.Resolver{
+ // PreferGo: true,
+ // Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
+ // d := net.Dialer{
+ // Timeout: time.Duration(dnsResolverTimeoutMs) * time.Millisecond,
+ // }
+ // return d.DialContext(ctx, dnsResolverProto, DnsResolverIP)
+ // },
+ // },
+ // }
+
+ return &http.Client{
+ Timeout: time.Hour * 48,
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+ // DialContext: dialer.DialContext,
+ IdleConnTimeout: IdleConnTimeout,
+ },
+ }
+}
+
+var isWorkPool *bool
+var proxyTimeout = int64(10)
+var mediaCache = cache.New(4*time.Hour, 10*time.Minute)
+
+type Chunk struct {
+ startOffset int64
+ endOffset int64
+ buffer []byte
+}
+
+func newChunk(start int64, end int64) *Chunk {
+ return &Chunk{
+ startOffset: start,
+ endOffset: end,
+ }
+}
+
+func (ch *Chunk) get() []byte {
+ return ch.buffer
+}
+
+func (ch *Chunk) put(buffer []byte) {
+ ch.buffer = buffer
+}
+
+type ProxyDownloadStruct struct {
+ ProxyRunning bool
+ NextChunkStartOffset int64
+ CurrentOffset int64
+ CurrentChunk int64
+ ChunkSize int64
+ MaxBufferedChunk int64
+ startOffset int64
+ EndOffset int64
+ ProxyMutex *sync.Mutex
+ ProxyTimeout int64
+ ReadyChunkQueue chan *Chunk
+ ThreadCount int64
+ DownloadUrl string
+ CookieJar *cookiejar.Jar
+ OriginThreadNum int
+}
+
+func newProxyDownloadStruct(downloadUrl string, proxyTimeout int64, maxBuferredChunk int64, chunkSize int64, startOffset int64, endOffset int64, numTasks int64, cookiejar *cookiejar.Jar, originThreadNum int) *ProxyDownloadStruct {
+ return &ProxyDownloadStruct{
+ ProxyRunning: true,
+ MaxBufferedChunk: int64(maxBuferredChunk),
+ ProxyTimeout: proxyTimeout,
+ ReadyChunkQueue: make(chan *Chunk, maxBuferredChunk),
+ ProxyMutex: &sync.Mutex{},
+ ChunkSize: chunkSize,
+ NextChunkStartOffset: startOffset,
+ CurrentOffset: startOffset,
+ startOffset: startOffset,
+ EndOffset: endOffset,
+ ThreadCount: numTasks,
+ DownloadUrl: downloadUrl,
+ CookieJar: cookiejar,
+ OriginThreadNum: originThreadNum,
+ }
+}
+
+func ConcurrentDownload(p *ProxyDownloadStruct, downloadUrl string, rangeStart int64, rangeEnd int64, splitSize int64, numTasks int64, emitter *Emitter, req *http.Request, jar *cookiejar.Jar) {
+ totalLength := rangeEnd - rangeStart + 1
+ numSplits := int64(totalLength/int64(splitSize)) + 1
+ if numSplits > int64(numTasks) {
+ numSplits = int64(numTasks)
+ }
+
+ log.Printf("[Debug] Processing: %+v, rangeStart: %+v, rangeEnd: %+v, contentLength :%+v, splitSize: %+v, numSplits: %+v, numTasks: %+v", downloadUrl, rangeStart, rangeEnd, totalLength, splitSize, numSplits, numTasks)
+
+ if *isWorkPool {
+ var wp *workpool.WorkPool
+ workPoolKey := downloadUrl + "#Workpool"
+ if x, found := mediaCache.Get(workPoolKey); found {
+ wp = x.(*workpool.WorkPool)
+ if isWorkPool == nil {
+ wp = workpool.New(int(numTasks))
+ wp.SetTimeout(time.Duration(proxyTimeout) * time.Second)
+ mediaCache.Set(workPoolKey, wp, 14400*time.Second)
+ }
+ } else {
+ wp = workpool.New(int(numTasks))
+ wp.SetTimeout(time.Duration(proxyTimeout) * time.Second)
+ mediaCache.Set(workPoolKey, wp, 14400*time.Second)
+ }
+ for numSplit := 0; numSplit < int(numSplits); numSplit++ {
+ wp.Do(func() error {
+ p.ProxyWorker(req)
+ return nil
+ })
+ }
+ } else {
+ for numSplit := 0; numSplit < int(numSplits); numSplit++ {
+ go p.ProxyWorker(req)
+ }
+ }
+
+ defer func() {
+ p.ProxyStop()
+ p = nil
+ }()
+
+ for {
+ buffer := p.ProxyRead()
+
+ if len(buffer) == 0 {
+ p.ProxyStop()
+ emitter.Close()
+ log.Printf("[Debug] ProxyRead failed")
+ buffer = nil
+ return
+ }
+
+ _, err := emitter.Write(buffer)
+
+ if err != nil {
+ p.ProxyStop()
+ emitter.Close()
+ log.Printf("[Error] emitter write failed, error: %+v", err)
+ buffer = nil
+ return
+ }
+
+ if p.CurrentOffset >= rangeEnd {
+ p.ProxyStop()
+ emitter.Close()
+ log.Printf("[Debug] All services have completed size: %+v", totalLength)
+ buffer = nil
+ return
+ }
+ buffer = nil
+ }
+}
+
+func (p *ProxyDownloadStruct) ProxyRead() []byte {
+ // Check if the file is downloaded
+ if p.CurrentOffset >= p.EndOffset {
+ p.ProxyStop()
+ return nil
+ }
+
+ // Get the data of the current chunk
+ var currentChunk *Chunk
+ select {
+ case currentChunk = <-p.ReadyChunkQueue:
+ break
+ case <-time.After(time.Duration(p.ProxyTimeout) * time.Second):
+ log.Printf("[Debug] ProxyRead execution timeout")
+ p.ProxyStop()
+ return nil
+ }
+
+ for {
+ if !p.ProxyRunning {
+ break
+ }
+ buffer := currentChunk.get()
+ if len(buffer) > 0 {
+ p.CurrentOffset += int64(len(buffer))
+ currentChunk = nil
+ return buffer
+ } else {
+ time.Sleep(50 * time.Millisecond)
+ }
+ }
+ currentChunk = nil
+ return nil
+}
+
+func (p *ProxyDownloadStruct) ProxyStop() {
+ p.ProxyRunning = false
+ var currentChunk *Chunk
+ for {
+ select {
+ case currentChunk = <-p.ReadyChunkQueue:
+ currentChunk.buffer = nil
+ currentChunk = nil
+ case <-time.After(1 * time.Second):
+ return
+ }
+ }
+}
+
+func (p *ProxyDownloadStruct) ProxyWorker(req *http.Request) {
+ log.Printf("[Debug] Current number of active goroutines: %d", runtime.NumGoroutine()-p.OriginThreadNum)
+ for {
+ if !p.ProxyRunning {
+ break
+ }
+
+ p.ProxyMutex.Lock()
+ // Generate the next chunk
+ var chunk *Chunk
+ chunk = nil
+ startOffset := p.NextChunkStartOffset
+ p.NextChunkStartOffset += p.ChunkSize
+ if startOffset <= p.EndOffset {
+ endOffset := startOffset + p.ChunkSize - 1
+ if endOffset > p.EndOffset {
+ endOffset = p.EndOffset
+ }
+ chunk = newChunk(startOffset, endOffset)
+
+ p.ReadyChunkQueue <- chunk
+ }
+ p.ProxyMutex.Unlock()
+
+ // All chunks are downloaded
+ if chunk == nil {
+ break
+ }
+
+ for {
+ if !p.ProxyRunning {
+ break
+ } else {
+ // Too much data is not taken, rest for a while to avoid memory overflow
+ remainingSize := p.GetRemainingSize(p.ChunkSize)
+ maxBufferSize := p.ChunkSize * p.MaxBufferedChunk
+ if remainingSize >= maxBufferSize {
+ log.Printf("[Debug] Unread data: %d >= buffer: %d , Rest for a while to avoid memory overflow", remainingSize, maxBufferSize)
+ time.Sleep(1 * time.Second)
+ } else {
+ // logrus.Debugf("未读取数据: %d < 缓冲区: %d , 下载继续", remainingSize, maxBufferSize)
+ break
+ }
+ }
+ }
+
+ for {
+ if !p.ProxyRunning {
+ break
+ } else {
+ // Establish connection
+ rangeStr := fmt.Sprintf("bytes=%d-%d", chunk.startOffset, chunk.endOffset)
+ newHeader := make(map[string][]string)
+ for key, value := range req.Header {
+ if !shouldFilterHeaderName(key) {
+ newHeader[key] = value
+ }
+ }
+
+ maxRetries := 5
+ if startOffset < int64(1048576) || (p.EndOffset-startOffset)/p.EndOffset*1000 < 2 {
+ maxRetries = 7
+ }
+
+ var resp *resty.Response
+ var err error
+ for retry := 0; retry < maxRetries; retry++ {
+ resp, err = RestyClient.
+ SetTimeout(10*time.Second).
+ SetRetryCount(1).
+ SetCookieJar(p.CookieJar).
+ R().
+ SetHeaderMultiValues(newHeader).
+ SetHeader("Range", rangeStr).
+ Get(p.DownloadUrl)
+
+ if err != nil {
+ log.Printf("[Error] Processing %+v link range=%d-%d partially failed: %+v", p.DownloadUrl, chunk.startOffset, chunk.endOffset, err)
+ time.Sleep(1 * time.Second)
+ resp = nil
+ continue
+ }
+ if !strings.HasPrefix(resp.Status(), "20") {
+ log.Printf("[Debug] Processing %+v link range=%d-%d partially failed, statusCode: %+v: %s", p.DownloadUrl, chunk.startOffset, chunk.endOffset, resp.StatusCode(), resp.String())
+ resp = nil
+ p.ProxyStop()
+ return
+ }
+ break
+ }
+
+ if err != nil {
+ resp = nil
+ p.ProxyStop()
+ return
+ }
+
+ // Receive data
+ if resp != nil && resp.Body() != nil {
+ buffer := make([]byte, chunk.endOffset-chunk.startOffset+1)
+ copy(buffer, resp.Body())
+ chunk.put(buffer)
+ }
+ resp = nil
+ break
+ }
+ }
+ }
+}
+
+func (p *ProxyDownloadStruct) GetRemainingSize(bufferSize int64) int64 {
+ p.ProxyMutex.Lock()
+ defer p.ProxyMutex.Unlock()
+ return int64(len(p.ReadyChunkQueue)) * bufferSize
+}
+
+func handleMethod(w http.ResponseWriter, req *http.Request) {
+ switch req.Method {
+ case http.MethodGet:
+ // Process GET requests
+ log.Printf("[Info] Processing GET request")
+ // Check if the query parameters are empty
+ if req.URL.RawQuery == "" {
+ // Get the embedded index.html file
+ http.Error(w, "Missing url parameter", http.StatusBadRequest)
+ return
+ } else {
+ // If there are query parameters, return custom content
+ handleGetMethod(w, req)
+ }
+ default:
+ // Process other method requests
+ log.Printf("[Info] Processing %v request", req.Method)
+ handleOtherMethod(w, req)
+ }
+}
+
+func handleGetMethod(w http.ResponseWriter, req *http.Request) {
+ pw := bufio.NewWriterSize(w, 128*1024)
+ defer func() {
+ if pw.Buffered() > 0 {
+ pw.Flush()
+ }
+ }()
+
+ var urlStr string
+ query := req.URL.Query()
+ urlStr = query.Get("url")
+ strForm := query.Get("form")
+ strHeader := query.Get("header")
+ strThread := req.URL.Query().Get("thread")
+ strSplitSize := req.URL.Query().Get("size")
+ quarkFids := query.Get("quarkfids")
+
+ if strHeader != "" {
+ if strForm == "base64" {
+ bytesStrHeader, err := base64.StdEncoding.DecodeString(strHeader)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Invalid Base64 Headers: %v", err), http.StatusBadRequest)
+ return
+ }
+ strHeader = string(bytesStrHeader)
+ }
+ var header map[string]string
+ err := json.Unmarshal([]byte(strHeader), &header)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Header Json format error: %v", err), http.StatusInternalServerError)
+ return
+ }
+ for key, value := range header {
+ req.Header.Set(key, value)
+ }
+ }
+
+ newHeader := make(map[string][]string)
+ for key, value := range req.Header {
+ if !shouldFilterHeaderName(key) {
+ newHeader[key] = value
+ }
+ }
+ if urlStr == "" && quarkFids != "" {
+ data := map[string]interface{}{
+ "fids": []string{quarkFids},
+ }
+ var apiResponse struct {
+ Data []struct {
+ DownloadUrl string `json:"download_url"`
+ } `json:"data"`
+ }
+ resp, err := RestyClient.
+ SetRetryCount(3).
+ R().
+ SetHeaderMultiValues(newHeader).
+ SetBody(data).
+ Post("https://drive-pc.quark.cn/1/clouddrive/file/download?pr=ucpro&fr=pc&uc_param_str=")
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Failed to download %v link: %v", urlStr, err), http.StatusInternalServerError)
+ return
+ }
+ err = json.Unmarshal(resp.Body(), &apiResponse)
+ if err != nil {
+ http.Error(w, "Failed to parse API response", http.StatusInternalServerError)
+ return
+ }
+
+ if len(apiResponse.Data) == 0 {
+ http.Error(w, "No download URL found", http.StatusNotFound)
+ return
+ }
+ urlStr = apiResponse.Data[0].DownloadUrl
+ // for key, value := range resp.Header() {
+ // if !shouldFilterHeaderName(key) {
+ // newHeader[key] = value
+ // }
+ // }
+ // req.Header = newHeader
+ }
+ if urlStr != "" {
+ if strForm == "base64" {
+ bytesUrl, err := base64.StdEncoding.DecodeString(urlStr)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Invalid Base64 Url: %v", err), http.StatusBadRequest)
+ return
+ }
+ urlStr = string(bytesUrl)
+ }
+ } else {
+ http.Error(w, "Missing url parameter", http.StatusBadRequest)
+ return
+ }
+
+ for parameterName := range query {
+ if parameterName == "url" || parameterName == "form" || parameterName == "thread" || parameterName == "size" || parameterName == "header" || parameterName == "quarkfids" {
+ continue
+ }
+ urlStr = urlStr + "&" + parameterName + "=" + query.Get(parameterName)
+ }
+
+ jar, _ := cookiejar.New(nil)
+ cookies := req.Cookies()
+ if len(cookies) > 0 {
+ // Add cookies to the cookie jar
+ u, _ := url.Parse(urlStr)
+ jar.SetCookies(u, cookies)
+ }
+
+ var statusCode int
+ var rangeStart, rangeEnd = int64(0), int64(0)
+ requestRange := req.Header.Get("Range")
+ rangeRegex := regexp.MustCompile(`bytes= *([0-9]+) *- *([0-9]*)`)
+ matchGroup := rangeRegex.FindStringSubmatch(requestRange)
+ if matchGroup != nil {
+ statusCode = 206
+ rangeStart, _ = strconv.ParseInt(matchGroup[1], 10, 64)
+ if len(matchGroup) > 2 {
+ rangeEnd, _ = strconv.ParseInt(matchGroup[2], 10, 64)
+ }
+ } else {
+ statusCode = 200
+ }
+
+ log.Printf("[Debug] Headers: %+v", newHeader)
+ headersKey := urlStr + "#Headers"
+ var responseHeaders interface{}
+ var connection = "keep-alive"
+ responseHeaders, found := mediaCache.Get(headersKey)
+ if !found {
+ // Close Idle timeout setting
+ IdleConnTimeout = 0
+ resp, err := RestyClient.
+ SetTimeout(0).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetDoNotParseResponse(true).
+ SetOutput(os.DevNull).
+ SetHeaderMultiValues(newHeader).
+ SetHeader("Range", "bytes=0-1023").
+ Get(urlStr)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Failed to download %v link: %v", urlStr, err), http.StatusInternalServerError)
+ return
+ }
+ if resp.StatusCode() < 200 || resp.StatusCode() >= 400 {
+ http.Error(w, resp.Status(), resp.StatusCode())
+ return
+ }
+ responseHeaders = resp.Header()
+
+ var fileName string
+ contentDisposition := strings.ToLower(responseHeaders.(http.Header).Get("Content-Disposition"))
+ if contentDisposition != "" {
+ regCompile := regexp.MustCompile(`^.*filename=\"([^\"]+)\".*$`)
+ if regCompile.MatchString(contentDisposition) {
+ fileName = regCompile.ReplaceAllString(contentDisposition, "$1")
+ }
+ } else {
+ // Find the index of the last "/"
+ lastSlashIndex := strings.LastIndex(urlStr, "/")
+ // Find the index of the first "?"
+ queryIndex := strings.Index(urlStr, "?")
+ if queryIndex == -1 {
+ // If there is no "?", extract the string from the last "/" to the end
+ fileName = urlStr[lastSlashIndex+1:]
+ } else {
+ // If there is a "?", extract the string from the last "/" to the "?"
+ fileName = urlStr[lastSlashIndex+1 : queryIndex]
+ }
+ }
+
+ contentType := responseHeaders.(http.Header).Get("Content-Type")
+ if contentType == "" || contentType == "application/octet-stream" {
+ if strings.HasSuffix(fileName, ".webm") {
+ contentType = "video/webm"
+ } else if strings.HasSuffix(fileName, ".avi") {
+ contentType = "video/x-msvideo"
+ } else if strings.HasSuffix(fileName, ".wmv") {
+ contentType = "video/x-ms-wmv"
+ } else if strings.HasSuffix(fileName, ".flv") {
+ contentType = "video/x-flv"
+ } else if strings.HasSuffix(fileName, ".mov") {
+ contentType = "video/quicktime"
+ } else if strings.HasSuffix(fileName, ".mkv") {
+ contentType = "video/x-matroska"
+ } else if strings.HasSuffix(fileName, ".ts") {
+ contentType = "video/mp2t"
+ } else if strings.HasSuffix(fileName, ".mpeg") || strings.HasSuffix(fileName, ".mpg") {
+ contentType = "video/mpeg"
+ } else if strings.HasSuffix(fileName, ".3gpp") || strings.HasSuffix(fileName, ".3gp") {
+ contentType = "video/3gpp"
+ } else if strings.HasSuffix(fileName, ".mp4") || strings.HasSuffix(fileName, ".m4s") {
+ contentType = "video/mp4"
+ }
+ responseHeaders.(http.Header).Set("Content-Type", contentType)
+ }
+
+ contentRange := responseHeaders.(http.Header).Get("Content-Range")
+ if contentRange != "" {
+ matchGroup := regexp.MustCompile(`.*/([0-9]+)`).FindStringSubmatch(contentRange)
+ contentSize, _ := strconv.ParseInt(matchGroup[1], 10, 64)
+ responseHeaders.(http.Header).Set("Content-Length", strconv.FormatInt(contentSize, 10))
+ } else {
+ if resp.Size() > 0 {
+ responseHeaders.(http.Header).Set("Content-Length", strconv.FormatInt(resp.Size(), 10))
+ } else {
+ responseHeaders.(http.Header).Set("Content-Length", strconv.FormatInt(resp.RawResponse.ContentLength, 10))
+ }
+
+ }
+
+ acceptRange := responseHeaders.(http.Header).Get("Accept-Ranges")
+ if contentRange == "" && acceptRange == "" {
+ // Not support resume download
+ log.Printf("[Debug] Not support resume download")
+ buf := make([]byte, 1024*64)
+ for {
+ n, err := resp.RawBody().Read(buf)
+ if n > 0 {
+ // Write data to client
+ _, writeErr := pw.Write(buf[:n])
+ if writeErr != nil {
+ http.Error(w, fmt.Sprintf("Failed to write Response to client: %v", writeErr), http.StatusInternalServerError)
+ return
+ }
+ }
+ if err != nil {
+ if err != io.EOF {
+ log.Printf("[Error] Read Response Body error: %v", err)
+ }
+ break
+ }
+ }
+ responseHeaders.(http.Header).Set("Content-Disposition", fmt.Sprintf("attachment; filename*=UTF-8''%s", fileName))
+
+ defer func() {
+ if resp != nil && resp.RawBody() != nil {
+ log.Printf("[Debug] resp.RawBody closed")
+ resp.RawBody().Close()
+ }
+ }()
+ } else {
+ // Support resume download
+ log.Printf("[Debug] Support resume download")
+ mediaCache.Set(headersKey, responseHeaders, 1800*time.Second)
+
+ if resp != nil && resp.RawBody() != nil {
+ log.Printf("[Debug] resp.RawBody closed")
+ resp.RawBody().Close()
+ }
+ }
+ }
+
+ acceptRange := responseHeaders.(http.Header).Get("Accept-Ranges")
+ contentRange := responseHeaders.(http.Header).Get("Content-Range")
+ if contentRange == "" && acceptRange == "" {
+ // Not support resume download
+ log.Printf("[Debug] Not support resume download-Get Headers from cache")
+ for key, values := range responseHeaders.(http.Header) {
+ if strings.EqualFold(strings.ToLower(key), "connection") || strings.EqualFold(strings.ToLower(key), "proxy-connection") {
+ continue
+ }
+ w.Header().Set(key, strings.Join(values, ","))
+ }
+ w.Header().Set("Connection", "keep-alive")
+ w.WriteHeader(statusCode)
+ } else {
+ // Support resume download
+ log.Printf("[Debug] Support resume download-Get Headers from cache")
+ responseHeaders.(http.Header).Del("Content-Range")
+ responseHeaders.(http.Header).Set("Accept-Ranges", "bytes")
+
+ var splitSize int64
+ var numTasks int64
+
+ contentSize := int64(0)
+ matchGroup = regexp.MustCompile(`.*/([0-9]+)`).FindStringSubmatch(contentRange)
+ if matchGroup != nil {
+ contentSize, _ = strconv.ParseInt(matchGroup[1], 10, 64)
+ } else {
+ contentSize, _ = strconv.ParseInt(responseHeaders.(http.Header).Get("Content-Length"), 10, 64)
+ }
+
+ if rangeEnd == int64(0) {
+ rangeEnd = contentSize - 1
+ }
+ if rangeStart < contentSize {
+ if strThread == "" {
+ if contentSize < 1*1024*1024*1024 {
+ numTasks = 4
+ } else if contentSize < 4*1024*1024*1024 {
+ numTasks = 8
+ } else if contentSize < 16*1024*1024*1024 {
+ numTasks = 12
+ } else {
+ numTasks = 16
+ }
+ } else {
+ numTasks, _ = strconv.ParseInt(strThread, 10, 64)
+ }
+
+ if numTasks <= 0 {
+ numTasks = 1
+ }
+
+ if strSplitSize != "" {
+ splitSize, _ = strconv.ParseInt(strSplitSize, 10, 64)
+ } else {
+ splitSize = int64(128 * 1024)
+ }
+ responseHeaders.(http.Header).Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", rangeStart, rangeEnd, contentSize))
+
+ for key, values := range responseHeaders.(http.Header) {
+ if strings.EqualFold(strings.ToLower(key), "connection") || strings.EqualFold(strings.ToLower(key), "proxy-connection") || strings.EqualFold(strings.ToLower(key), "transfer-encoding") {
+ continue
+ }
+ if statusCode == 200 && strings.EqualFold(strings.ToLower(key), "content-range") {
+ continue
+ } else if statusCode == 206 && strings.EqualFold(strings.ToLower(key), "accept-ranges") {
+ continue
+ }
+ w.Header().Set(key, strings.Join(values, ","))
+ }
+ w.Header().Set("Connection", "keep-alive")
+ w.WriteHeader(statusCode)
+
+ rp, wp := io.Pipe()
+ emitter := NewEmitter(rp, wp)
+
+ maxChunks := int64(128*1024*1024) / splitSize
+ p := newProxyDownloadStruct(urlStr, proxyTimeout, maxChunks, splitSize, rangeStart, rangeEnd, numTasks, jar, runtime.NumGoroutine()+1)
+
+ go ConcurrentDownload(p, urlStr, rangeStart, rangeEnd, splitSize, numTasks, emitter, req, jar)
+ io.Copy(pw, emitter)
+
+ defer func() {
+ log.Printf("[Debug] handleGetMethod emitter closed-Support resume download")
+ p.ProxyStop()
+ p = nil
+ emitter.Close()
+ }()
+
+ } else {
+ statusCode = 200
+ connection = "close"
+ for key, values := range responseHeaders.(http.Header) {
+ if strings.EqualFold(strings.ToLower(key), "connection") || strings.EqualFold(strings.ToLower(key), "proxy-connection") || strings.EqualFold(strings.ToLower(key), "transfer-encoding") {
+ continue
+ }
+ w.Header().Del(key)
+ w.Header().Set(key, strings.Join(values, ","))
+ }
+ w.Header().Set("Connection", connection)
+ w.WriteHeader(statusCode)
+ }
+ }
+}
+
+func handleOtherMethod(w http.ResponseWriter, req *http.Request) {
+ defer req.Body.Close()
+
+ var urlStr string
+ query := req.URL.Query()
+ urlStr = query.Get("url")
+ strForm := query.Get("form")
+ strHeader := query.Get("header")
+
+ if urlStr != "" {
+ if strForm == "base64" {
+ bytesUrl, err := base64.StdEncoding.DecodeString(urlStr)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Invalid Base64 Url: %v", err), http.StatusBadRequest)
+ return
+ }
+ urlStr = string(bytesUrl)
+ }
+ } else {
+ http.Error(w, "Missing url parameter", http.StatusBadRequest)
+ return
+ }
+
+ // Process custom header
+ var header map[string]string
+ if strHeader != "" {
+ if strForm == "base64" {
+ bytesStrHeader, err := base64.StdEncoding.DecodeString(strHeader)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Invalid Base64 Headers: %v", err), http.StatusBadRequest)
+ return
+ }
+ strHeader = string(bytesStrHeader)
+ }
+ err := json.Unmarshal([]byte(strHeader), &header)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Header Json format error: %v", err), http.StatusInternalServerError)
+ return
+ }
+ for key, value := range header {
+ req.Header.Set(key, value)
+ }
+ }
+ newHeader := make(map[string][]string)
+ for key, value := range req.Header {
+ if !shouldFilterHeaderName(key) {
+ newHeader[key] = value
+ }
+ }
+
+ // Build new URL
+ for parameterName := range query {
+ if parameterName == "url" || parameterName == "form" || parameterName == "thread" || parameterName == "size" || parameterName == "header" {
+ continue
+ }
+ urlStr = urlStr + "&" + parameterName + "=" + query.Get(parameterName)
+ }
+
+ jar, _ := cookiejar.New(nil)
+ cookies := req.Cookies()
+ if len(cookies) > 0 {
+ // Add cookies to the cookie jar
+ u, _ := url.Parse(req.URL.String())
+ jar.SetCookies(u, cookies)
+ }
+
+ var reqBody []byte
+ // Read request body to record
+ if req.Body != nil {
+ reqBody, _ = io.ReadAll(req.Body)
+ }
+
+ var resp *resty.Response
+ var err error
+ switch req.Method {
+ case http.MethodPost:
+ resp, err = RestyClient.
+ SetTimeout(10 * time.Second).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetBody(reqBody).
+ SetHeaderMultiValues(newHeader).
+ Post(urlStr)
+ case http.MethodPut:
+ resp, err = RestyClient.
+ SetTimeout(10 * time.Second).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetBody(reqBody).
+ SetHeaderMultiValues(newHeader).
+ Put(urlStr)
+ case http.MethodOptions:
+ resp, err = RestyClient.
+ SetTimeout(10 * time.Second).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetHeaderMultiValues(newHeader).
+ Options(urlStr)
+ case http.MethodDelete:
+ resp, err = RestyClient.
+ SetTimeout(10 * time.Second).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetHeaderMultiValues(newHeader).
+ Delete(urlStr)
+ case http.MethodPatch:
+ resp, err = RestyClient.
+ SetTimeout(10 * time.Second).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetHeaderMultiValues(newHeader).
+ Patch(urlStr)
+ case http.MethodHead:
+ resp, err = RestyClient.
+ SetTimeout(10 * time.Second).
+ SetRetryCount(3).
+ SetCookieJar(jar).
+ R().
+ SetHeaderMultiValues(newHeader).
+ Head(urlStr)
+ default:
+ http.Error(w, fmt.Sprintf("Invalid Method: %v", req.Method), http.StatusBadRequest)
+ }
+
+ if err != nil {
+ http.Error(w, fmt.Sprintf("%v link %v failed: %v", req.Method, urlStr, err), http.StatusInternalServerError)
+ resp = nil
+ return
+ }
+ if resp.StatusCode() < 200 || resp.StatusCode() >= 400 {
+ http.Error(w, resp.Status(), resp.StatusCode())
+ resp = nil
+ return
+ }
+
+ // Process response
+ w.Header().Set("Connection", "close")
+ for key, values := range resp.Header() {
+ w.Header().Set(key, strings.Join(values, ","))
+ }
+ w.WriteHeader(resp.StatusCode())
+ bodyReader := bytes.NewReader(resp.Body())
+ io.Copy(w, bodyReader)
+}
+
+func shouldFilterHeaderName(key string) bool {
+ if len(strings.TrimSpace(key)) == 0 {
+ return false
+ }
+ key = strings.ToLower(key)
+ return key == "range" || key == "host" || key == "http-client-ip" || key == "remote-addr" || key == "accept-encoding"
+}
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/Info.plist
index 23651a26..24afd6a3 100644
--- a/ios/Frameworks/Libmtorrentserver.xcframework/Info.plist
+++ b/ios/Frameworks/Libmtorrentserver.xcframework/Info.plist
@@ -5,6 +5,8 @@
AvailableLibraries
+ BinaryPath
+ Libmtorrentserver.framework/Libmtorrentserver
LibraryIdentifier
ios-arm64
LibraryPath
@@ -17,6 +19,8 @@
ios
+ BinaryPath
+ Libmtorrentserver.framework/Libmtorrentserver
LibraryIdentifier
ios-arm64_x86_64-simulator
LibraryPath
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Info.plist
new file mode 100644
index 00000000..c70dc8d3
--- /dev/null
+++ b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Info.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ CFBundleExecutable
+ Libmtorrentserver
+ CFBundleIdentifier
+ Libmtorrentserver
+ MinimumOSVersion
+ 100.0
+ CFBundleShortVersionString
+ 0.0.1729240882
+ CFBundleVersion
+ 0.0.1729240882
+ CFBundlePackageType
+ FMWK
+
+
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Libmtorrentserver b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Libmtorrentserver
index 5752d650..47ca2945 100644
Binary files a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Libmtorrentserver and b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Libmtorrentserver differ
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Resources/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Resources/Info.plist
deleted file mode 100644
index 0d1a4b8a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Resources/Info.plist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.h
deleted file mode 100644
index 31a091b2..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.h
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// Objective-C API for talking to the following Go packages
-//
-// server/binding/mobile
-//
-// File is generated by gomobile bind. Do not edit.
-#ifndef __Libmtorrentserver_FRAMEWORK_H__
-#define __Libmtorrentserver_FRAMEWORK_H__
-
-#include "Libmtorrentserver.objc.h"
-#include "Universe.objc.h"
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.objc.h
deleted file mode 100644
index 3052338a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.objc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Objective-C API for talking to server/binding/mobile Go package.
-// gobind -lang=objc server/binding/mobile
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Libmtorrentserver_H__
-#define __Libmtorrentserver_H__
-
-@import Foundation;
-#include "ref.h"
-#include "Universe.objc.h"
-
-
-FOUNDATION_EXPORT BOOL LibmtorrentserverStart(NSString* _Nullable mcfg, long* _Nullable ret0_, NSError* _Nullable* _Nullable error);
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Universe.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Universe.objc.h
deleted file mode 100644
index 019e7502..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/Universe.objc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Objective-C API for talking to Go package.
-// gobind -lang=objc
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Universe_H__
-#define __Universe_H__
-
-@import Foundation;
-#include "ref.h"
-
-@protocol Universeerror;
-@class Universeerror;
-
-@protocol Universeerror
-- (NSString* _Nonnull)error;
-@end
-
-@class Universeerror;
-
-@interface Universeerror : NSError {
-}
-@property(strong, readonly) _Nonnull id _ref;
-
-- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
-- (NSString* _Nonnull)error;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/ref.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/ref.h
deleted file mode 100644
index b8036a4d..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Headers/ref.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef __GO_REF_HDR__
-#define __GO_REF_HDR__
-
-#include
-
-// GoSeqRef is an object tagged with an integer for passing back and
-// forth across the language boundary. A GoSeqRef may represent either
-// an instance of a Go object, or an Objective-C object passed to Go.
-// The explicit allocation of a GoSeqRef is used to pin a Go object
-// when it is passed to Objective-C. The Go seq package maintains a
-// reference to the Go object in a map keyed by the refnum along with
-// a reference count. When the reference count reaches zero, the Go
-// seq package will clear the corresponding entry in the map.
-@interface GoSeqRef : NSObject {
-}
-@property(readonly) int32_t refnum;
-@property(strong) id obj; // NULL when representing a Go object.
-
-// new GoSeqRef object to proxy a Go object. The refnum must be
-// provided from Go side.
-- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
-
-- (int32_t)incNum;
-
-@end
-
-@protocol goSeqRefInterface
--(GoSeqRef*) _ref;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Libmtorrentserver b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Libmtorrentserver
deleted file mode 100644
index 5752d650..00000000
Binary files a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Libmtorrentserver and /dev/null differ
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Modules/module.modulemap b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Modules/module.modulemap
deleted file mode 100644
index c4d4f78c..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Modules/module.modulemap
+++ /dev/null
@@ -1,8 +0,0 @@
-framework module "Libmtorrentserver" {
- header "ref.h"
- header "Libmtorrentserver.objc.h"
- header "Universe.objc.h"
- header "Libmtorrentserver.h"
-
- export *
-}
\ No newline at end of file
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Resources/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Resources/Info.plist
deleted file mode 100644
index 0d1a4b8a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/A/Resources/Info.plist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.h
deleted file mode 100644
index 31a091b2..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.h
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// Objective-C API for talking to the following Go packages
-//
-// server/binding/mobile
-//
-// File is generated by gomobile bind. Do not edit.
-#ifndef __Libmtorrentserver_FRAMEWORK_H__
-#define __Libmtorrentserver_FRAMEWORK_H__
-
-#include "Libmtorrentserver.objc.h"
-#include "Universe.objc.h"
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.objc.h
deleted file mode 100644
index 3052338a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.objc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Objective-C API for talking to server/binding/mobile Go package.
-// gobind -lang=objc server/binding/mobile
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Libmtorrentserver_H__
-#define __Libmtorrentserver_H__
-
-@import Foundation;
-#include "ref.h"
-#include "Universe.objc.h"
-
-
-FOUNDATION_EXPORT BOOL LibmtorrentserverStart(NSString* _Nullable mcfg, long* _Nullable ret0_, NSError* _Nullable* _Nullable error);
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Universe.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Universe.objc.h
deleted file mode 100644
index 019e7502..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/Universe.objc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Objective-C API for talking to Go package.
-// gobind -lang=objc
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Universe_H__
-#define __Universe_H__
-
-@import Foundation;
-#include "ref.h"
-
-@protocol Universeerror;
-@class Universeerror;
-
-@protocol Universeerror
-- (NSString* _Nonnull)error;
-@end
-
-@class Universeerror;
-
-@interface Universeerror : NSError {
-}
-@property(strong, readonly) _Nonnull id _ref;
-
-- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
-- (NSString* _Nonnull)error;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/ref.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/ref.h
deleted file mode 100644
index b8036a4d..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Headers/ref.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef __GO_REF_HDR__
-#define __GO_REF_HDR__
-
-#include
-
-// GoSeqRef is an object tagged with an integer for passing back and
-// forth across the language boundary. A GoSeqRef may represent either
-// an instance of a Go object, or an Objective-C object passed to Go.
-// The explicit allocation of a GoSeqRef is used to pin a Go object
-// when it is passed to Objective-C. The Go seq package maintains a
-// reference to the Go object in a map keyed by the refnum along with
-// a reference count. When the reference count reaches zero, the Go
-// seq package will clear the corresponding entry in the map.
-@interface GoSeqRef : NSObject {
-}
-@property(readonly) int32_t refnum;
-@property(strong) id obj; // NULL when representing a Go object.
-
-// new GoSeqRef object to proxy a Go object. The refnum must be
-// provided from Go side.
-- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
-
-- (int32_t)incNum;
-
-@end
-
-@protocol goSeqRefInterface
--(GoSeqRef*) _ref;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Libmtorrentserver b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Libmtorrentserver
deleted file mode 100644
index 5752d650..00000000
Binary files a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Libmtorrentserver and /dev/null differ
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Modules/module.modulemap b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Modules/module.modulemap
deleted file mode 100644
index c4d4f78c..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Modules/module.modulemap
+++ /dev/null
@@ -1,8 +0,0 @@
-framework module "Libmtorrentserver" {
- header "ref.h"
- header "Libmtorrentserver.objc.h"
- header "Universe.objc.h"
- header "Libmtorrentserver.h"
-
- export *
-}
\ No newline at end of file
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Resources/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Resources/Info.plist
deleted file mode 100644
index 0d1a4b8a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64/Libmtorrentserver.framework/Versions/Current/Resources/Info.plist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Info.plist
new file mode 100644
index 00000000..c70dc8d3
--- /dev/null
+++ b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Info.plist
@@ -0,0 +1,18 @@
+
+
+
+
+ CFBundleExecutable
+ Libmtorrentserver
+ CFBundleIdentifier
+ Libmtorrentserver
+ MinimumOSVersion
+ 100.0
+ CFBundleShortVersionString
+ 0.0.1729240882
+ CFBundleVersion
+ 0.0.1729240882
+ CFBundlePackageType
+ FMWK
+
+
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Libmtorrentserver b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Libmtorrentserver
index 9d9086e1..62949e31 100644
Binary files a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Libmtorrentserver and b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Libmtorrentserver differ
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Resources/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Resources/Info.plist
deleted file mode 100644
index 0d1a4b8a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Resources/Info.plist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.h
deleted file mode 100644
index 31a091b2..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.h
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// Objective-C API for talking to the following Go packages
-//
-// server/binding/mobile
-//
-// File is generated by gomobile bind. Do not edit.
-#ifndef __Libmtorrentserver_FRAMEWORK_H__
-#define __Libmtorrentserver_FRAMEWORK_H__
-
-#include "Libmtorrentserver.objc.h"
-#include "Universe.objc.h"
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.objc.h
deleted file mode 100644
index 3052338a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Libmtorrentserver.objc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Objective-C API for talking to server/binding/mobile Go package.
-// gobind -lang=objc server/binding/mobile
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Libmtorrentserver_H__
-#define __Libmtorrentserver_H__
-
-@import Foundation;
-#include "ref.h"
-#include "Universe.objc.h"
-
-
-FOUNDATION_EXPORT BOOL LibmtorrentserverStart(NSString* _Nullable mcfg, long* _Nullable ret0_, NSError* _Nullable* _Nullable error);
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Universe.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Universe.objc.h
deleted file mode 100644
index 019e7502..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/Universe.objc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Objective-C API for talking to Go package.
-// gobind -lang=objc
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Universe_H__
-#define __Universe_H__
-
-@import Foundation;
-#include "ref.h"
-
-@protocol Universeerror;
-@class Universeerror;
-
-@protocol Universeerror
-- (NSString* _Nonnull)error;
-@end
-
-@class Universeerror;
-
-@interface Universeerror : NSError {
-}
-@property(strong, readonly) _Nonnull id _ref;
-
-- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
-- (NSString* _Nonnull)error;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/ref.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/ref.h
deleted file mode 100644
index b8036a4d..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Headers/ref.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef __GO_REF_HDR__
-#define __GO_REF_HDR__
-
-#include
-
-// GoSeqRef is an object tagged with an integer for passing back and
-// forth across the language boundary. A GoSeqRef may represent either
-// an instance of a Go object, or an Objective-C object passed to Go.
-// The explicit allocation of a GoSeqRef is used to pin a Go object
-// when it is passed to Objective-C. The Go seq package maintains a
-// reference to the Go object in a map keyed by the refnum along with
-// a reference count. When the reference count reaches zero, the Go
-// seq package will clear the corresponding entry in the map.
-@interface GoSeqRef : NSObject {
-}
-@property(readonly) int32_t refnum;
-@property(strong) id obj; // NULL when representing a Go object.
-
-// new GoSeqRef object to proxy a Go object. The refnum must be
-// provided from Go side.
-- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
-
-- (int32_t)incNum;
-
-@end
-
-@protocol goSeqRefInterface
--(GoSeqRef*) _ref;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Libmtorrentserver b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Libmtorrentserver
deleted file mode 100644
index 9d9086e1..00000000
Binary files a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Libmtorrentserver and /dev/null differ
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Modules/module.modulemap b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Modules/module.modulemap
deleted file mode 100644
index c4d4f78c..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Modules/module.modulemap
+++ /dev/null
@@ -1,8 +0,0 @@
-framework module "Libmtorrentserver" {
- header "ref.h"
- header "Libmtorrentserver.objc.h"
- header "Universe.objc.h"
- header "Libmtorrentserver.h"
-
- export *
-}
\ No newline at end of file
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Resources/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Resources/Info.plist
deleted file mode 100644
index 0d1a4b8a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/A/Resources/Info.plist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.h
deleted file mode 100644
index 31a091b2..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.h
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// Objective-C API for talking to the following Go packages
-//
-// server/binding/mobile
-//
-// File is generated by gomobile bind. Do not edit.
-#ifndef __Libmtorrentserver_FRAMEWORK_H__
-#define __Libmtorrentserver_FRAMEWORK_H__
-
-#include "Libmtorrentserver.objc.h"
-#include "Universe.objc.h"
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.objc.h
deleted file mode 100644
index 3052338a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Libmtorrentserver.objc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Objective-C API for talking to server/binding/mobile Go package.
-// gobind -lang=objc server/binding/mobile
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Libmtorrentserver_H__
-#define __Libmtorrentserver_H__
-
-@import Foundation;
-#include "ref.h"
-#include "Universe.objc.h"
-
-
-FOUNDATION_EXPORT BOOL LibmtorrentserverStart(NSString* _Nullable mcfg, long* _Nullable ret0_, NSError* _Nullable* _Nullable error);
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Universe.objc.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Universe.objc.h
deleted file mode 100644
index 019e7502..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/Universe.objc.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Objective-C API for talking to Go package.
-// gobind -lang=objc
-//
-// File is generated by gobind. Do not edit.
-
-#ifndef __Universe_H__
-#define __Universe_H__
-
-@import Foundation;
-#include "ref.h"
-
-@protocol Universeerror;
-@class Universeerror;
-
-@protocol Universeerror
-- (NSString* _Nonnull)error;
-@end
-
-@class Universeerror;
-
-@interface Universeerror : NSError {
-}
-@property(strong, readonly) _Nonnull id _ref;
-
-- (nonnull instancetype)initWithRef:(_Nonnull id)ref;
-- (NSString* _Nonnull)error;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/ref.h b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/ref.h
deleted file mode 100644
index b8036a4d..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Headers/ref.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#ifndef __GO_REF_HDR__
-#define __GO_REF_HDR__
-
-#include
-
-// GoSeqRef is an object tagged with an integer for passing back and
-// forth across the language boundary. A GoSeqRef may represent either
-// an instance of a Go object, or an Objective-C object passed to Go.
-// The explicit allocation of a GoSeqRef is used to pin a Go object
-// when it is passed to Objective-C. The Go seq package maintains a
-// reference to the Go object in a map keyed by the refnum along with
-// a reference count. When the reference count reaches zero, the Go
-// seq package will clear the corresponding entry in the map.
-@interface GoSeqRef : NSObject {
-}
-@property(readonly) int32_t refnum;
-@property(strong) id obj; // NULL when representing a Go object.
-
-// new GoSeqRef object to proxy a Go object. The refnum must be
-// provided from Go side.
-- (instancetype)initWithRefnum:(int32_t)refnum obj:(id)obj;
-
-- (int32_t)incNum;
-
-@end
-
-@protocol goSeqRefInterface
--(GoSeqRef*) _ref;
-@end
-
-#endif
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Libmtorrentserver b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Libmtorrentserver
deleted file mode 100644
index 9d9086e1..00000000
Binary files a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Libmtorrentserver and /dev/null differ
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Modules/module.modulemap b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Modules/module.modulemap
deleted file mode 100644
index c4d4f78c..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Modules/module.modulemap
+++ /dev/null
@@ -1,8 +0,0 @@
-framework module "Libmtorrentserver" {
- header "ref.h"
- header "Libmtorrentserver.objc.h"
- header "Universe.objc.h"
- header "Libmtorrentserver.h"
-
- export *
-}
\ No newline at end of file
diff --git a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Resources/Info.plist b/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Resources/Info.plist
deleted file mode 100644
index 0d1a4b8a..00000000
--- a/ios/Frameworks/Libmtorrentserver.xcframework/ios-arm64_x86_64-simulator/Libmtorrentserver.framework/Versions/Current/Resources/Info.plist
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/lib/eval/dart/model/m_bridge.dart b/lib/eval/dart/model/m_bridge.dart
index 89814b17..3acab5e6 100644
--- a/lib/eval/dart/model/m_bridge.dart
+++ b/lib/eval/dart/model/m_bridge.dart
@@ -348,31 +348,38 @@ class MBridge {
.videosFromUrl(url, newHeaders, prefix: prefix, suffix: suffix);
}
- static Future>> quarkFilesExtractor(
- List url, String cookie) async {
- QuarkUcExtractor quark = QuarkUcExtractor();
- await quark.initCloudDrive(cookie, CloudDriveType.quark);
- return await quark.videoFilesFromUrl(url);
+ static final Map _extractorCache = {};
+
+ static QuarkUcExtractor _getExtractor(String cookie, CloudDriveType type) {
+ if (!_extractorCache.containsKey(type)) {
+ QuarkUcExtractor extractor = QuarkUcExtractor();
+ extractor.initCloudDrive(cookie, type);
+ _extractorCache[type] = extractor;
+ }
+ return _extractorCache[type]!;
}
- static Future>> ucFilesExtractor(
+ static Future>> quarkFilesExtractor(
List url, String cookie) async {
- QuarkUcExtractor uc = QuarkUcExtractor();
- await uc.initCloudDrive(cookie, CloudDriveType.uc);
- return await uc.videoFilesFromUrl(url);
+ var quark = _getExtractor(cookie, CloudDriveType.quark);
+ return await quark.videoFilesFromUrl(url);
}
static Future> quarkVideosExtractor(
String url, String cookie) async {
- QuarkUcExtractor quark = QuarkUcExtractor();
- await quark.initCloudDrive(cookie, CloudDriveType.quark);
+ var quark = _getExtractor(cookie, CloudDriveType.quark);
return await quark.videosFromUrl(url);
}
+ static Future>> ucFilesExtractor(
+ List url, String cookie) async {
+ var uc = _getExtractor(cookie, CloudDriveType.uc);
+ return await uc.videoFilesFromUrl(url);
+ }
+
static Future> ucVideosExtractor(
String url, String cookie) async {
- QuarkUcExtractor uc = QuarkUcExtractor();
- await uc.initCloudDrive(cookie, CloudDriveType.uc);
+ var uc = _getExtractor(cookie, CloudDriveType.uc);
return await uc.videosFromUrl(url);
}
diff --git a/lib/services/anime_extractors/quarkuc_extractor.dart b/lib/services/anime_extractors/quarkuc_extractor.dart
index 732fb436..29f718e2 100644
--- a/lib/services/anime_extractors/quarkuc_extractor.dart
+++ b/lib/services/anime_extractors/quarkuc_extractor.dart
@@ -4,6 +4,7 @@ import 'dart:math';
import 'package:http_interceptor/http_interceptor.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/services/http/m_client.dart';
+import 'package:mangayomi/services/torrent_server.dart';
enum CloudDriveType {
quark,
@@ -32,6 +33,7 @@ class QuarkUcExtractor {
apiUrl = "https://pc-api.uc.cn/1/clouddrive/";
pr = "pr=UCBrowser&fr=pc";
}
+ MTorrentServer().ensureRunning();
}
Map getHeaders() {
@@ -42,7 +44,7 @@ class QuarkUcExtractor {
'Referer': 'https://pan.quark.cn/',
"Content-Type": "application/json",
"Cookie": cookie,
- "Host": "drive-pc.quark.cn"
+ // "Host": "drive-pc.quark.cn"
};
} else {
return {
@@ -51,7 +53,7 @@ class QuarkUcExtractor {
'Referer': 'https://drive.uc.cn/',
"Content-Type": "application/json",
"Cookie": cookie,
- "Host": "pc-api.uc.cn"
+ // "Host": "pc-api.uc.cn"
};
}
}
@@ -305,8 +307,8 @@ class QuarkUcExtractor {
return null;
}
- Future getLiveTranscoding(String shareId, String stoken,
- String fileId, String fileToken, String quality) async {
+ Future>?> getLiveTranscoding(
+ String shareId, String stoken, String fileId, String fileToken) async {
if (!saveFileIdCaches.containsKey(fileId)) {
final saveFileId = await save(shareId, stoken, fileId, fileToken, true);
if (saveFileId == null) return null;
@@ -322,13 +324,15 @@ class QuarkUcExtractor {
'post');
if (transcoding['data'] != null &&
transcoding['data']['video_list'] != null) {
+ List