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> qualityOptions = []; for (final video in transcoding['data']['video_list']) { - if (video['resolution'] == quality) { - return video['video_info']['url']; - } + // qualityOptions[video['resolution']] = video['video_info']['url']; + qualityOptions.add({ + 'url': video['video_info']['url'], + 'quality': video['resolution'] + }); } - // 如果没有找到匹配的质量,返回null - return null; + return qualityOptions; } return null; } @@ -340,6 +344,8 @@ class QuarkUcExtractor { if (saveFileId == null) return null; saveFileIdCaches[fileId] = saveFileId; } + var headers = getHeaders(); + headers.remove('Content-Type'); final down = await api( 'file/download?$pr&uc_param_str=', { @@ -347,7 +353,10 @@ class QuarkUcExtractor { }, 'post'); if (down['data'] != null) { - return down['data'][0]; + return { + 'downloadInfo': down['data'][0], + 'headers': headers, + }; } return null; } @@ -399,46 +408,43 @@ class QuarkUcExtractor { String type = parts[0]; List subtitleParts = parts.length > 5 ? parts[5].split('+') : []; // 获取可用的质量列表 - List qualities = getPlayFormtList(); + //List qualities = getPlayFormtList(); List