Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7fefd2b9b | ||
|
|
b8e36b483e | ||
|
|
91ac841b9d | ||
|
|
5134446c3f | ||
|
|
82b6ebd6f1 | ||
|
|
f8ea009fe9 | ||
|
|
070db64ca9 | ||
|
|
6a8956b04d | ||
|
|
057504bb81 | ||
|
|
470b488824 | ||
|
|
c8c9df1ae8 | ||
|
|
33d787c74e | ||
|
|
67338a5e83 | ||
|
|
723697192d | ||
|
|
4294d07d6a | ||
|
|
3936fd786f | ||
|
|
45197e9a3b | ||
|
|
c9692e76e5 | ||
|
|
0a9e39ed75 | ||
|
|
1971f582b5 | ||
|
|
c62d6be3da | ||
|
|
7d5e503894 | ||
|
|
6c4066fde4 | ||
|
|
ffdf3e717f | ||
|
|
f66814b4ae | ||
|
|
0c3e201a51 | ||
|
|
c32a5d750f | ||
|
|
207c287c97 | ||
|
|
56ef25065e | ||
|
|
bd6d6be71f | ||
|
|
1d3a028bae | ||
|
|
27011fb96b | ||
|
|
c696b59c4b | ||
|
|
78b5b8a78b | ||
|
|
c81ca7f5cd | ||
|
|
e39d50fe09 | ||
|
|
086269f8bd | ||
|
|
00d2183961 | ||
|
|
5f914dc4c4 | ||
|
|
9bf204cf04 | ||
|
|
a816b9ccc8 | ||
|
|
d60d370463 | ||
|
|
84d054b494 | ||
|
|
1aa96e147f | ||
|
|
8c01e45780 | ||
|
|
8ad571aa08 | ||
|
|
39316e9b8e | ||
|
|
f778596390 | ||
|
|
c2cbc14492 | ||
|
|
62c22bc6b4 | ||
|
|
b89c7bc608 | ||
|
|
f2cd686563 | ||
|
|
ef5ee99f04 | ||
|
|
6d136604db | ||
|
|
38ff711ea9 | ||
|
|
a1a8abc25f |
No files matched your search
@@ -16,7 +16,7 @@ categories:
|
|||||||
- title: '🧰 Maintenance'
|
- title: '🧰 Maintenance'
|
||||||
label: 'chore'
|
label: 'chore'
|
||||||
- title: '📖 Document'
|
- title: '📖 Document'
|
||||||
label: 'doc'
|
label: 'docs'
|
||||||
- title: '🚀 CI/CD'
|
- title: '🚀 CI/CD'
|
||||||
label: 'ci'
|
label: 'ci'
|
||||||
- title: '🌎 Internationalization'
|
- title: '🌎 Internationalization'
|
||||||
@@ -34,7 +34,7 @@ version-resolver:
|
|||||||
- 'patch'
|
- 'patch'
|
||||||
default: patch
|
default: patch
|
||||||
template: |
|
template: |
|
||||||
# Changes
|
# Release notes
|
||||||
|
|
||||||
$CHANGES
|
$CHANGES
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ on:
|
|||||||
description: 'Build platform'
|
description: 'Build platform'
|
||||||
required: true
|
required: true
|
||||||
default: 'all'
|
default: 'all'
|
||||||
channel:
|
test:
|
||||||
description: 'Snap channel'
|
description: 'Test mode'
|
||||||
required: true
|
required: true
|
||||||
default: 'stable'
|
default: "false"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: "1.19"
|
GO_VERSION: "1.21"
|
||||||
FLUTTER_VERSION: "3.16.1"
|
FLUTTER_VERSION: "3.16.8"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -23,11 +23,11 @@ jobs:
|
|||||||
get-release:
|
get-release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
tag_name: ${{ steps.get-release.outputs.tag_name }}
|
version: ${{ steps.get-release.outputs.version }}
|
||||||
upload_url: ${{ steps.get-release.outputs.upload_url }}
|
upload_url: ${{ steps.get-release.outputs.upload_url }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: monkeyWie/get-latest-release@v1
|
- uses: monkeyWie/get-latest-release@v2.1
|
||||||
id: get-release
|
id: get-release
|
||||||
with:
|
with:
|
||||||
myToken: ${{ github.token }}
|
myToken: ${{ github.token }}
|
||||||
@@ -40,19 +40,20 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: "1.20"
|
go-version: ${{ env.GO_VERSION }}
|
||||||
- uses: subosito/flutter-action@v2
|
- uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
Invoke-WebRequest -Uri "https://github.com/jrsoftware/issrc/raw/main/Files/Languages/Unofficial/ChineseSimplified.isl" -OutFile "ChineseSimplified.isl"
|
Invoke-WebRequest -Uri "https://github.com/jrsoftware/issrc/raw/main/Files/Languages/Unofficial/ChineseSimplified.isl" -OutFile "ChineseSimplified.isl"
|
||||||
mv ChineseSimplified.isl "C:\Program Files (x86)\Inno Setup 6\Languages\"
|
mv ChineseSimplified.isl "C:\Program Files (x86)\Inno Setup 6\Languages\"
|
||||||
|
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/windows/libgopeed.dll github.com/GopeedLab/gopeed/bind/desktop
|
go build -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -buildmode=c-shared -o ui/flutter/windows/libgopeed.dll github.com/GopeedLab/gopeed/bind/desktop
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
|
$TAG = "v$env:VERSION"
|
||||||
flutter build windows
|
flutter build windows
|
||||||
$mingw = "C:\Program Files\Git\mingw64\bin"
|
$mingw = "C:\Program Files\Git\mingw64\bin"
|
||||||
$system = "C:\Windows\System32"
|
$system = "C:\Windows\System32"
|
||||||
@@ -65,7 +66,7 @@ jobs:
|
|||||||
cp $system\vcruntime140_1.dll $release
|
cp $system\vcruntime140_1.dll $release
|
||||||
|
|
||||||
New-Item -Path build\windows\Output -ItemType Directory
|
New-Item -Path build\windows\Output -ItemType Directory
|
||||||
Compress-Archive -Path "$release*" -DestinationPath "build\windows\Output\Gopeed-$env:VERSION-windows-amd64-portable.zip"
|
Compress-Archive -Path "$release*" -DestinationPath "build\windows\Output\Gopeed-$TAG-windows-amd64-portable.zip"
|
||||||
|
|
||||||
cd build/windows
|
cd build/windows
|
||||||
echo @"
|
echo @"
|
||||||
@@ -73,7 +74,7 @@ jobs:
|
|||||||
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
|
||||||
|
|
||||||
#define MyAppName "Gopeed"
|
#define MyAppName "Gopeed"
|
||||||
#define MyAppVersion "$($env:VERSION.substring(1))"
|
#define MyAppVersion "$env:VERSION"
|
||||||
#define MyAppPublisher "monkeyWie"
|
#define MyAppPublisher "monkeyWie"
|
||||||
#define MyAppURL "https://gopeed.com"
|
#define MyAppURL "https://gopeed.com"
|
||||||
#define MyAppExeName "gopeed.exe"
|
#define MyAppExeName "gopeed.exe"
|
||||||
@@ -124,9 +125,9 @@ jobs:
|
|||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||||
"@ > setup.iss
|
"@ > setup.iss
|
||||||
iscc.exe setup.iss
|
iscc.exe setup.iss
|
||||||
mv "Output\gopeed.exe" "Output\Gopeed-$env:VERSION-windows-amd64.exe"
|
mv "Output\gopeed.exe" "Output\Gopeed-$TAG-windows-amd64.exe"
|
||||||
Compress-Archive -Path "Output\Gopeed-$env:VERSION-windows-amd64.exe" -DestinationPath "Output\Gopeed-$env:VERSION-windows-amd64.zip"
|
Compress-Archive -Path "Output\Gopeed-$TAG-windows-amd64.exe" -DestinationPath "Output\Gopeed-$TAG-windows-amd64.zip"
|
||||||
Remove-Item -Path "Output\Gopeed-$env:VERSION-windows-amd64.exe"
|
Remove-Item -Path "Output\Gopeed-$TAG-windows-amd64.exe"
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
uses: shogo82148/actions-upload-release-asset@v1
|
||||||
with:
|
with:
|
||||||
@@ -143,9 +144,11 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
- name: Build
|
- name: Build
|
||||||
|
env:
|
||||||
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
go install src.techknowlogick.com/xgo@latest
|
go install src.techknowlogick.com/xgo@latest
|
||||||
xgo -go go-$GO_VERSION.x --targets=darwin/arm64 -tags="nosqlite" -ldflags="-w -s" -buildmode=c-shared -pkg=bind/desktop -out=libgopeed .
|
xgo -go go-$GO_VERSION.x --targets=darwin/arm64 -tags="nosqlite" -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -buildmode=c-shared -pkg=bind/desktop -out=libgopeed .
|
||||||
mv libgopeed-*.dylib libgopeed.dylib
|
mv libgopeed-*.dylib libgopeed.dylib
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
@@ -176,12 +179,12 @@ jobs:
|
|||||||
path: ui/flutter/lib-arm64
|
path: ui/flutter/lib-arm64
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
PROJECT_DIR=$(pwd)
|
PROJECT_DIR=$(pwd)
|
||||||
|
|
||||||
# amd64 lib
|
# amd64 lib
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/lib-amd64/libgopeed.dylib github.com/GopeedLab/gopeed/bind/desktop
|
go build -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -buildmode=c-shared -o ui/flutter/lib-amd64/libgopeed.dylib github.com/GopeedLab/gopeed/bind/desktop
|
||||||
# universal binary
|
# universal binary
|
||||||
mkdir -p ui/flutter/macos/Frameworks
|
mkdir -p ui/flutter/macos/Frameworks
|
||||||
cp ui/flutter/lib-amd64/libgopeed.dylib ui/flutter/macos/Frameworks/amd64-lib
|
cp ui/flutter/lib-amd64/libgopeed.dylib ui/flutter/macos/Frameworks/amd64-lib
|
||||||
@@ -203,7 +206,7 @@ jobs:
|
|||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
mkdir dist
|
mkdir dist
|
||||||
appdmg appdmg.json dist/Gopeed-$VERSION-macos.dmg
|
appdmg appdmg.json dist/Gopeed-v$VERSION-macos.dmg
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
uses: shogo82148/actions-upload-release-asset@v1
|
||||||
with:
|
with:
|
||||||
@@ -212,7 +215,7 @@ jobs:
|
|||||||
overwrite: true
|
overwrite: true
|
||||||
build-linux:
|
build-linux:
|
||||||
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'linux' }}
|
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'linux' }}
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
needs: [ get-release ]
|
needs: [ get-release ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -225,9 +228,7 @@ jobs:
|
|||||||
- run: |
|
- run: |
|
||||||
sudo apt update -y
|
sudo apt update -y
|
||||||
# flutter build dependencies
|
# flutter build dependencies
|
||||||
sudo apt install -y ninja-build libgtk-3-dev libappindicator3-dev
|
sudo apt install -y ninja-build libgtk-3-dev libayatana-appindicator3-1 libayatana-appindicator3-dev
|
||||||
# rpm build dependencies
|
|
||||||
sudo apt install -y rpm patchelf
|
|
||||||
# appimage build dependencies
|
# appimage build dependencies
|
||||||
sudo apt install -y libfuse2 locate
|
sudo apt install -y libfuse2 locate
|
||||||
wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||||
@@ -235,15 +236,15 @@ jobs:
|
|||||||
sudo mv appimagetool /usr/local/bin/
|
sudo mv appimagetool /usr/local/bin/
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
go build -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
dart pub global activate -sgit https://github.com/GopeedLab/flutter_distributor.git --git-path packages/flutter_distributor
|
dart pub global activate -sgit https://github.com/GopeedLab/flutter_distributor.git --git-path packages/flutter_distributor
|
||||||
flutter_distributor package --platform linux --targets appimage,deb
|
flutter_distributor package --platform linux --targets appimage,deb
|
||||||
cd dist/*
|
cd dist/*
|
||||||
mv gopeed-*-linux.AppImage Gopeed-${VERSION}-linux-x86_64.AppImage
|
mv gopeed-*-linux.AppImage Gopeed-v${VERSION}-linux-x86_64.AppImage
|
||||||
mv gopeed-*-linux.deb Gopeed-${VERSION}-linux-amd64.deb
|
mv gopeed-*-linux.deb Gopeed-v${VERSION}-linux-amd64.deb
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
uses: shogo82148/actions-upload-release-asset@v1
|
||||||
with:
|
with:
|
||||||
@@ -268,9 +269,9 @@ jobs:
|
|||||||
channel: latest/stable
|
channel: latest/stable
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
go build -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
|
|
||||||
sudo snap install snapcraft --classic
|
sudo snap install snapcraft --classic
|
||||||
@@ -279,7 +280,7 @@ jobs:
|
|||||||
|
|
||||||
cat>snap/snapcraft.yaml<<EOF
|
cat>snap/snapcraft.yaml<<EOF
|
||||||
name: gopeed
|
name: gopeed
|
||||||
version: ${VERSION:1}
|
version: $VERSION
|
||||||
summary: A modern download manager
|
summary: A modern download manager
|
||||||
description: High speed downloader that supports all platforms.
|
description: High speed downloader that supports all platforms.
|
||||||
|
|
||||||
@@ -322,7 +323,7 @@ jobs:
|
|||||||
|
|
||||||
# Snapcraft login
|
# Snapcraft login
|
||||||
export SNAPCRAFT_STORE_CREDENTIALS=${{ secrets.SNAP_STORE_LOGIN }}
|
export SNAPCRAFT_STORE_CREDENTIALS=${{ secrets.SNAP_STORE_LOGIN }}
|
||||||
snapcraft upload --release=${{ github.event.inputs.channel }} gopeed_${VERSION:1}_amd64.snap
|
snapcraft upload --release=${{ github.event.inputs.test == 'true' && 'edge' || 'stable' }} gopeed_${VERSION}_amd64.snap
|
||||||
build-android:
|
build-android:
|
||||||
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'android' }}
|
if: ${{ github.event.inputs.platform == 'all' || github.event.inputs.platform == 'android' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -341,7 +342,7 @@ jobs:
|
|||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
APK_KEYSTORE: ${{ secrets.APK_KEYSTORE }}
|
APK_KEYSTORE: ${{ secrets.APK_KEYSTORE }}
|
||||||
APK_KEY_PASSWORD: ${{ secrets.APK_KEY_PASSWORD }}
|
APK_KEY_PASSWORD: ${{ secrets.APK_KEY_PASSWORD }}
|
||||||
APK_STORE_PASSWORD: ${{ secrets.APK_STORE_PASSWORD }}
|
APK_STORE_PASSWORD: ${{ secrets.APK_STORE_PASSWORD }}
|
||||||
@@ -349,12 +350,12 @@ jobs:
|
|||||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
go get golang.org/x/mobile/bind
|
go get golang.org/x/mobile/bind
|
||||||
gomobile init
|
gomobile init
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
gomobile bind -tags nosqlite -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
echo $APK_KEYSTORE | base64 -di > android/app/upload-keystore.jks
|
echo $APK_KEYSTORE | base64 -di > android/app/upload-keystore.jks
|
||||||
flutter build apk
|
flutter build apk
|
||||||
mkdir dist
|
mkdir dist
|
||||||
cp build/app/outputs/flutter-apk/app-release.apk dist/Gopeed-$VERSION-android.apk
|
cp build/app/outputs/flutter-apk/app-release.apk dist/Gopeed-v$VERSION-android.apk
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
uses: shogo82148/actions-upload-release-asset@v1
|
||||||
with:
|
with:
|
||||||
@@ -375,19 +376,19 @@ jobs:
|
|||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
go install golang.org/x/mobile/cmd/gomobile@latest
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
go get golang.org/x/mobile/bind
|
go get golang.org/x/mobile/bind
|
||||||
gomobile init
|
gomobile init
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/ios/Frameworks/Libgopeed.xcframework -target=ios github.com/GopeedLab/gopeed/bind/mobile
|
gomobile bind -tags nosqlite,netgo -ldflags="-w -s -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -o ui/flutter/ios/Frameworks/Libgopeed.xcframework -target=ios github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build ios --no-codesign
|
flutter build ios --no-codesign
|
||||||
mkdir Payload
|
mkdir Payload
|
||||||
cp -r build/ios/iphoneos/Runner.app Payload
|
cp -r build/ios/iphoneos/Runner.app Payload
|
||||||
zip -r -y Payload.zip Payload/Runner.app
|
zip -r -y Payload.zip Payload/Runner.app
|
||||||
mkdir dist
|
mkdir dist
|
||||||
mv Payload.zip dist/Gopeed-$VERSION-ios.ipa
|
mv Payload.zip dist/Gopeed-v$VERSION-ios.ipa
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: shogo82148/actions-upload-release-asset@v1
|
uses: shogo82148/actions-upload-release-asset@v1
|
||||||
with:
|
with:
|
||||||
@@ -408,13 +409,14 @@ jobs:
|
|||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
run: |
|
run: |
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build web --web-renderer html
|
flutter build web --web-renderer html
|
||||||
cd ../../
|
cd ../../
|
||||||
cp -r ui/flutter/build/web cmd/web/dist
|
cp -r ui/flutter/build/web cmd/web/dist
|
||||||
mkdir -p dist/zip
|
mkdir -p dist/zip
|
||||||
|
|
||||||
goos_arr=(windows darwin linux)
|
goos_arr=(windows darwin linux)
|
||||||
goarch_arr=(386 amd64 arm64)
|
goarch_arr=(386 amd64 arm64)
|
||||||
export CGO_ENABLED=0
|
export CGO_ENABLED=0
|
||||||
@@ -424,9 +426,9 @@ jobs:
|
|||||||
if [ $goos = "darwin" ]; then
|
if [ $goos = "darwin" ]; then
|
||||||
goos_name="macos"
|
goos_name="macos"
|
||||||
fi
|
fi
|
||||||
name=gopeed-web-$VERSION-$goos_name-$goarch
|
name=gopeed-web-v$VERSION-$goos_name-$goarch
|
||||||
dir="dist/$name/"
|
dir="dist/$name/"
|
||||||
(GOOS=$goos GOARCH=$goarch go build -tags nosqlite,web -ldflags="-s -w" -o $dir github.com/GopeedLab/gopeed/cmd/web \
|
(GOOS=$goos GOARCH=$goarch go build -tags nosqlite,web -ldflags="-s -w -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION" -o $dir github.com/GopeedLab/gopeed/cmd/web \
|
||||||
&& cd $dir \
|
&& cd $dir \
|
||||||
&& file=$(ls -AU | head -1) \
|
&& file=$(ls -AU | head -1) \
|
||||||
&& mkdir $name \
|
&& mkdir $name \
|
||||||
@@ -464,15 +466,18 @@ jobs:
|
|||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ needs.get-release.outputs.tag_name }}
|
VERSION: ${{ needs.get-release.outputs.version }}
|
||||||
with:
|
with:
|
||||||
push: true
|
push: ${{ github.event.inputs.test == 'true' && 'false' || 'true' }}
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ env.VERSION }}
|
||||||
|
IN_DOCKER=true
|
||||||
platforms: |
|
platforms: |
|
||||||
linux/386
|
linux/386
|
||||||
linux/amd64
|
linux/amd64
|
||||||
linux/arm64
|
linux/arm64
|
||||||
linux/arm/v6
|
|
||||||
linux/arm/v7
|
linux/arm/v7
|
||||||
|
linux/arm64/v8
|
||||||
tags: |
|
tags: |
|
||||||
liwei2633/gopeed:latest
|
liwei2633/gopeed:latest
|
||||||
liwei2633/gopeed:${{ env.VERSION }}
|
liwei2633/gopeed:v${{ env.VERSION }}
|
||||||
@@ -27,8 +27,8 @@ on:
|
|||||||
- "go.sum"
|
- "go.sum"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: "1.19"
|
GO_VERSION: "1.21"
|
||||||
FLUTTER_VERSION: "3.16.1"
|
FLUTTER_VERSION: "3.16.8"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# lint:
|
# lint:
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Hướng dẫn đóng góp cho Gopeed
|
||||||
|
|
||||||
|
Trước tiên, cảm ơn bạn đã quan tâm đến việc đóng góp cho Gopeed. Hướng dẫn này sẽ giúp bạn tham gia
|
||||||
|
phát triển Gopeed một cách tốt hơn.
|
||||||
|
|
||||||
|
## Mô tả nhánh
|
||||||
|
|
||||||
|
Dự án này chỉ có một nhánh chính duy nhất, đó là nhánh `main`. Nếu bạn muốn tham gia vào
|
||||||
|
phát triển Gopeed, hãy fork dự án này trước, sau đó phát triển trong dự án fork của bạn. Sau khi
|
||||||
|
hoàn thành phát triển, gửi một PR đến dự án này và merge vào nhánh `main`.
|
||||||
|
|
||||||
|
## Phát triển cục bộ
|
||||||
|
|
||||||
|
Đề nghị phát triển và gỡ lỗi thông qua web. Đầu tiên, khởi động dịch vụ backend bằng cách chạy
|
||||||
|
lệnh `go run cmd/api/main.go` trong dòng lệnh, cổng mặc định của dịch vụ là `9999`, sau đó
|
||||||
|
khởi động dự án flutter frontend trong chế độ `debug` để chạy.
|
||||||
|
|
||||||
|
## Dịch thuật
|
||||||
|
|
||||||
|
Các tệp quốc tế hóa của Gopeed được đặt trong thư mục `ui/flutter/lib/i18n/langs`.
|
||||||
|
Bạn chỉ cần thêm tệp ngôn ngữ tương ứng trong thư mục này.
|
||||||
|
|
||||||
|
Vui lòng tham khảo `en_us.dart` để biết cách dịch thuật.
|
||||||
|
|
||||||
|
## Phát triển flutter
|
||||||
|
|
||||||
|
Đừng quên chạy `dart format ./ui/flutter` trước khi commit để giữ mã của bạn theo định dạng dart chuẩn.
|
||||||
|
|
||||||
|
Bật build_runner watcher nếu bạn muốn chỉnh sửa api/models:
|
||||||
@@ -1,22 +1,32 @@
|
|||||||
FROM instrumentisto/flutter:3.16.1 AS flutter
|
FROM instrumentisto/flutter:3.16.8 AS flutter
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./ui/flutter/pubspec.yaml ./ui/flutter/pubspec.lock ./
|
COPY ./ui/flutter/pubspec.yaml ./ui/flutter/pubspec.lock ./
|
||||||
RUN flutter pub get
|
RUN flutter pub get
|
||||||
COPY ./ui/flutter ./
|
COPY ./ui/flutter ./
|
||||||
RUN flutter build web --web-renderer html
|
RUN flutter build web --web-renderer html
|
||||||
|
|
||||||
FROM golang:1.19.3 AS go
|
FROM golang:1.21.6 AS go
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY ./go.mod ./go.sum ./
|
COPY ./go.mod ./go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
COPY . .
|
COPY . .
|
||||||
COPY --from=flutter /app/build/web ./cmd/web/dist
|
COPY --from=flutter /app/build/web ./cmd/web/dist
|
||||||
RUN CGO_ENABLED=0 go build -tags nosqlite,web -ldflags="-s -w" -o dist/gopeed github.com/GopeedLab/gopeed/cmd/web
|
ARG VERSION=dev
|
||||||
|
RUN CGO_ENABLED=0 go build -tags nosqlite,web \
|
||||||
|
-ldflags="-s -w -X github.com/GopeedLab/gopeed/pkg/base.Version=$VERSION -X github.com/GopeedLab/gopeed/pkg/base.InDocker=true" \
|
||||||
|
-o dist/gopeed github.com/GopeedLab/gopeed/cmd/web
|
||||||
|
|
||||||
FROM alpine:3.14.2
|
FROM alpine:3.14.2
|
||||||
LABEL maintainer="monkeyWie"
|
LABEL maintainer="monkeyWie"
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=go /app/dist/gopeed ./
|
COPY --from=go /app/dist/gopeed ./
|
||||||
|
COPY entrypoint.sh ./entrypoint.sh
|
||||||
|
RUN apk update && \
|
||||||
|
apk upgrade --no-cache && \
|
||||||
|
apk add --no-cache bash su-exec; \
|
||||||
|
chmod +x ./entrypoint.sh && \
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
VOLUME ["/app/storage"]
|
VOLUME ["/app/storage"]
|
||||||
|
ENV PUID=0 PGID=0 UMASK=022
|
||||||
EXPOSE 9999
|
EXPOSE 9999
|
||||||
ENTRYPOINT ["./gopeed"]
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
@@ -9,30 +9,80 @@
|
|||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md)
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
Gopeed (full name Go Speed), a high-speed downloader developed by `Golang` + `Flutter`, supports (HTTP, BitTorrent, Magnet) protocol, and supports all platforms. In addition to basic download functions, Gopeed is also a highly customizable downloader that supports implementing more features through integration with [APIs](https://docs.gopeed.com/dev-api.html) or installation and development of [extensions](https://docs.gopeed.com/dev-extension.html).
|
Gopeed (full name Go Speed), a high-speed downloader developed by `Golang` + `Flutter`, supports (HTTP, BitTorrent, Magnet) protocol, and supports all platforms. In addition to basic download functions, Gopeed is also a highly customizable downloader that supports implementing more features through integration with [APIs](https://docs.gopeed.com/dev-api.html) or installation and development of [extensions](https://docs.gopeed.com/dev-extension.html).
|
||||||
|
|
||||||
|
|
||||||
Visit ✈ [Official Website](https://gopeed.com) | 📖 [Official Docs](https://docs.gopeed.com)
|
Visit ✈ [Official Website](https://gopeed.com) | 📖 [Official Docs](https://docs.gopeed.com)
|
||||||
|
|
||||||
## Install
|
## Download
|
||||||
|
|
||||||
**Supported platforms**
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Platform</th>
|
||||||
|
<th>Package Type</th>
|
||||||
|
<th>Download Link</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=2>Windows</td>
|
||||||
|
<td><code>EXE Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable ZIP</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MacOS</td>
|
||||||
|
<td><code>DMG Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=4>Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>DEB</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>AppImage</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-x86_64.AppImage">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Android</td>
|
||||||
|
<td><code>APK</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Web</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://github.com/GopeedLab/gopeed/releases/latest">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
- [x] windows
|
More about installation, please refer to [Installation](https://docs.gopeed.com/install.html)
|
||||||
- [x] macos
|
|
||||||
- [x] linux
|
|
||||||
- [x] android
|
|
||||||
- [x] ios
|
|
||||||
- [x] web
|
|
||||||
- [x] docker
|
|
||||||
|
|
||||||
[Download](https://github.com/GopeedLab/gopeed/releases/latest)
|
|
||||||
|
|
||||||
> Tips: If the macos open failed, please execute the `xattr -d com.apple.quarantine /Applications/Gopeed.app` command in the terminal
|
|
||||||
|
|
||||||
### Command tool
|
### Command tool
|
||||||
|
|
||||||
@@ -42,25 +92,9 @@ use `go install`:
|
|||||||
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Docker
|
## Browser Extension
|
||||||
|
|
||||||
#### Start directly
|
Gopeed also provides a browser extension to take over browser downloads, supporting browsers such as Chrome, Edge, Firefox, etc., please refer to: [https://github.com/GopeedLab/browser-extension](https://github.com/GopeedLab/browser-extension)
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/root/Downloads -v /path/to/storage:/app/storage liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
[More details for docker](https://docs.gopeed.com/install.html#docker-installation)
|
|
||||||
|
|
||||||
#### Using Docker Compose
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Access Gopeed
|
|
||||||
|
|
||||||
When the docker container is running, you can access the web page through `http://localhost:9999`.
|
|
||||||
|
|
||||||
## Donate
|
## Donate
|
||||||
|
|
||||||
@@ -78,8 +112,8 @@ This project is divided into two parts, the front end uses `flutter`, the back e
|
|||||||
|
|
||||||
### Environment
|
### Environment
|
||||||
|
|
||||||
1. Golang 1.19+
|
1. Golang 1.21+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.16+
|
||||||
|
|
||||||
### Clone
|
### Clone
|
||||||
|
|
||||||
@@ -138,7 +172,7 @@ command:
|
|||||||
- android
|
- android
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md)
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
## はじめに
|
## はじめに
|
||||||
|
|
||||||
@@ -19,51 +19,74 @@ Gopeed (正式名 Go Speed) は `Golang` + `Flutter` によって開発された
|
|||||||
|
|
||||||
## インストール
|
## インストール
|
||||||
|
|
||||||
**サポートするプラットフォーム**
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Platform</th>
|
||||||
|
<th>Package Type</th>
|
||||||
|
<th>Download Link</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=2>Windows</td>
|
||||||
|
<td><code>EXE Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable ZIP</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MacOS</td>
|
||||||
|
<td><code>DMG Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=4>Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>DEB</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>AppImage</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-x86_64.AppImage">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Android</td>
|
||||||
|
<td><code>APK</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Web</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://github.com/GopeedLab/gopeed/releases/latest">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">Link</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
- [x] windows
|
インストールについての詳細は、[インストール](https://docs.gopeed.com/install.html)を参照してください。
|
||||||
- [x] macos
|
|
||||||
- [x] linux
|
|
||||||
- [x] android
|
|
||||||
- [x] ios
|
|
||||||
- [x] web
|
|
||||||
- [x] docker
|
|
||||||
|
|
||||||
[ダウンロード](https://github.com/GopeedLab/gopeed/releases/latest)
|
|
||||||
|
|
||||||
> ヒント: macos を開くのに失敗した場合は、ターミナルで `xattr -d com.apple.quarantine /Applications/Gopeed.app` コマンドを実行してください
|
|
||||||
|
|
||||||
### コマンドツール
|
|
||||||
|
|
||||||
`go install` を使用:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
#### 直接始める
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/root/Downloads -v /path/to/storage:/app/storage liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
[Dockerの使用については](https://docs.gopeed.com/install.html#docker-installation)
|
|
||||||
|
|
||||||
#### Docker Compose の使用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Gopeed へのアクセス
|
|
||||||
|
|
||||||
docker コンテナが起動しているときは、`http://localhost:9999` からウェブページにアクセスできます。
|
|
||||||
|
|
||||||
## 寄付
|
## 寄付
|
||||||
|
|
||||||
もしこのプロジェクトがお気に召しましたら、このプロジェクトの発展を支援するために[寄付](/.donate/index.md#donate)をご検討ください!
|
もしこのプロジェクトがお気に召しましたら、このプロジェクトの発展を支援するために[寄付](https://docs.gopeed.com/donate.html)をご検討ください!
|
||||||
|
|
||||||
## ショーケース
|
## ショーケース
|
||||||
|
|
||||||
@@ -77,8 +100,8 @@ docker コンテナが起動しているときは、`http://localhost:9999` か
|
|||||||
|
|
||||||
### 環境
|
### 環境
|
||||||
|
|
||||||
1. Go 言語 1.19+
|
1. Go 言語 1.21+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.16+
|
||||||
|
|
||||||
### クローン
|
### クローン
|
||||||
|
|
||||||
@@ -137,7 +160,7 @@ gomobile init
|
|||||||
- android
|
- android
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,211 @@
|
|||||||
|
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
||||||
|
[](https://codecov.io/gh/GopeedLab/gopeed)
|
||||||
|
[](https://github.com/GopeedLab/gopeed/releases)
|
||||||
|
[](https://github.com/GopeedLab/gopeed/releases)
|
||||||
|
[](https://docs.gopeed.com/donate.html)
|
||||||
|
[](https://discord.gg/ZUJqJrwCGB)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
|
## Giới thiệu
|
||||||
|
|
||||||
|
Gopeed (tên đầy đủ Go Speed), một công cụ tải xuống tốc độ cao được phát triển bởi `Golang` + `Flutter`, hỗ trợ giao thức (HTTP, BitTorrent, Magnet) và hỗ trợ tất cả các nền tảng. Ngoài các chức năng tải xuống cơ bản, Gopeed còn là một công cụ tải xuống có thể tùy chỉnh cao cho phép triển khai thêm tính năng thông qua việc tích hợp với [APIs](https://docs.gopeed.com/dev-api.html) hoặc cài đặt và phát triển các [tiện ích mở rộng](https://docs.gopeed.com/dev-extension.html).
|
||||||
|
|
||||||
|
Truy cập ✈ [Trang web chính thức](https://gopeed.com) | 📖 [Tài liệu chính thức](https://docs.gopeed.com)
|
||||||
|
|
||||||
|
## Tải về
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nền tảng</th>
|
||||||
|
<th>Loại gói</th>
|
||||||
|
<th>Liên kết tải xuống</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=2>Windows</td>
|
||||||
|
<td><code>Bộ cài đặt EXE</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>ZIP Portable</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MacOS</td>
|
||||||
|
<td><code>Bộ cài đặt DMG</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=4>Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>DEB</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>AppImage</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-x86_64.AppImage">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Android</td>
|
||||||
|
<td><code>APK</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Web</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://github.com/GopeedLab/gopeed/releases/latest">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">Liên kết</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Thêm thông tin về cài đặt, vui lòng tham khảo [Cài đặt](https://docs.gopeed.com/install.html)
|
||||||
|
|
||||||
|
### Command tool
|
||||||
|
|
||||||
|
Sử dụng `go install`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quyên góp
|
||||||
|
|
||||||
|
Nếu bạn thích dự án này, xin vui lòng xem xét [quyên góp](https://docs.gopeed.com/donate.html) để hỗ trợ phát triển dự án này, cảm ơn bạn!
|
||||||
|
|
||||||
|
## Trưng bày
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Dự án này được chia thành hai phần, phần giao diện sử dụng `flutter`, phần backend sử dụng `Golang`, và hai phía giao tiếp thông qua giao thức `http`. Trên hệ thống unix, sử dụng `unix socket`, và trên hệ thống windows, sử dụng giao thức `tcp`.
|
||||||
|
|
||||||
|
> Mã giao diện nằm trong thư mục `ui/flutter`.
|
||||||
|
|
||||||
|
### Environment
|
||||||
|
|
||||||
|
1. Golang 1.21+
|
||||||
|
2. Flutter 3.16+
|
||||||
|
|
||||||
|
### Clone
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone [email protected]:GopeedLab/gopeed.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### Đóng góp
|
||||||
|
|
||||||
|
Vui lòng tham khảo [CONTRIBUTING_vi-VN.md](/CONTRIBUTING_vi-VN.md)
|
||||||
|
|
||||||
|
### Xây dựng
|
||||||
|
|
||||||
|
#### Desktop
|
||||||
|
|
||||||
|
Trước tiên, bạn cần cấu hình môi trường theo tài liệu chính thức của [Tài liệu trang web máy tính để bàn Flutter](https://docs.flutter.dev/development/platform-integration/desktop), sau đó bạn cần đảm bảo môi trường cgo được thiết lập đúng. Để biết hướng dẫn chi tiết về cách thiết lập môi trường cgo, vui lòng tham khảo các tài liệu tương ứng có sẵn trực tuyến.
|
||||||
|
|
||||||
|
command:
|
||||||
|
|
||||||
|
- windows
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/windows/libgopeed.dll github.com/GopeedLab/gopeed/bind/desktop
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build windows
|
||||||
|
```
|
||||||
|
|
||||||
|
- macos
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/macos/Frameworks/libgopeed.dylib github.com/GopeedLab/gopeed/bind/desktop
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build macos
|
||||||
|
```
|
||||||
|
|
||||||
|
- linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -tags nosqlite -ldflags="-w -s" -buildmode=c-shared -o ui/flutter/linux/bundle/lib/libgopeed.so github.com/GopeedLab/gopeed/bind/desktop
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build linux
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Mobile
|
||||||
|
|
||||||
|
Giống như trước đây, bạn cũng cần chuẩn bị môi trường `cgo` và sau đó cài đặt `gomobile`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
|
go get golang.org/x/mobile/bind
|
||||||
|
gomobile init
|
||||||
|
```
|
||||||
|
|
||||||
|
command:
|
||||||
|
|
||||||
|
- android
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build apk
|
||||||
|
```
|
||||||
|
|
||||||
|
- ios
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/ios/Frameworks/Libgopeed.xcframework -target=ios github.com/GopeedLab/gopeed/bind/mobile
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build ios --no-codesign
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Web
|
||||||
|
|
||||||
|
command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build web
|
||||||
|
cd ../../
|
||||||
|
rm -rf cmd/web/dist
|
||||||
|
cp -r ui/flutter/build/web cmd/web/dist
|
||||||
|
go build -tags nosqlite,web -ldflags="-s -w" -o bin/ github.com/GopeedLab/gopeed/cmd/web
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tín dụng
|
||||||
|
|
||||||
|
### Người đóng góp
|
||||||
|
|
||||||
|
<a href="https://github.com/GopeedLab/gopeed/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=GopeedLab/gopeed" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
### JetBrains
|
||||||
|
|
||||||
|
[](https://www.jetbrains.com/?from=gopeed)
|
||||||
|
|
||||||
|
## Giấy phép
|
||||||
|
|
||||||
|
[GPLv3](LICENSE)
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md)
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
## 介绍
|
## 介绍
|
||||||
|
|
||||||
@@ -17,21 +17,72 @@ Gopeed(全称 Go Speed),直译过来中文名叫做`够快下载器`(不
|
|||||||
|
|
||||||
访问 ✈ [官方网站](https://gopeed.com/zh-CN) | 📖 [官方文档](https://docs.gopeed.com/zh/)
|
访问 ✈ [官方网站](https://gopeed.com/zh-CN) | 📖 [官方文档](https://docs.gopeed.com/zh/)
|
||||||
|
|
||||||
## 安装
|
## 下载
|
||||||
|
|
||||||
**已支持平台**
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>运行平台</th>
|
||||||
|
<th>安装包类型</th>
|
||||||
|
<th>下载链接</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=2>Windows</td>
|
||||||
|
<td><code>EXE Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable ZIP</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MacOS</td>
|
||||||
|
<td><code>DMG Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=4>Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>DEB</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>AppImage</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-x86_64.AppImage">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Android</td>
|
||||||
|
<td><code>APK</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Web</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://github.com/GopeedLab/gopeed/releases/latest">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
- [x] windows
|
更多关于安装的内容请参考[安装文档](https://docs.gopeed.com/zh/install.html)
|
||||||
- [x] macos
|
|
||||||
- [x] linux
|
|
||||||
- [x] android
|
|
||||||
- [x] ios
|
|
||||||
- [x] web
|
|
||||||
- [x] docker
|
|
||||||
|
|
||||||
[前往下载](https://github.com/GopeedLab/gopeed/releases/latest)
|
|
||||||
|
|
||||||
> 注:macos 版本运行如果提示损坏,请在终端执行 `xattr -d com.apple.quarantine /Applications/Gopeed.app` 命令
|
|
||||||
|
|
||||||
### 命令行工具
|
### 命令行工具
|
||||||
|
|
||||||
@@ -41,25 +92,9 @@ Gopeed(全称 Go Speed),直译过来中文名叫做`够快下载器`(不
|
|||||||
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Docker
|
## 浏览器扩展
|
||||||
|
|
||||||
#### 直接运行
|
Gopeed 还提供了浏览器扩展用于接管浏览器下载,支持 Chrome、Edge、Firefox 等浏览器,具体请参考:[https://github.com/GopeedLab/browser-extension](https://github.com/GopeedLab/browser-extension)
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/root/Downloads -v /path/to/storage:/app/storage liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
[更多关于 Docker 的使用](https://docs.gopeed.com/zh/install.html#docker-%E5%AE%89%E8%A3%85)
|
|
||||||
|
|
||||||
#### 使用 Docker Compose
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 访问服务
|
|
||||||
|
|
||||||
当 docker 容器运行时,可以通过 `http://localhost:9999` 访问 web 页面。
|
|
||||||
|
|
||||||
## 赞助
|
## 赞助
|
||||||
|
|
||||||
@@ -77,8 +112,8 @@ docker-compose up -d
|
|||||||
|
|
||||||
### 环境要求
|
### 环境要求
|
||||||
|
|
||||||
1. Golang 1.19+
|
1. Golang 1.21+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.16+
|
||||||
|
|
||||||
### 克隆项目
|
### 克隆项目
|
||||||
|
|
||||||
@@ -137,7 +172,7 @@ gomobile init
|
|||||||
- android
|
- android
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md)
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
## 簡介
|
## 簡介
|
||||||
|
|
||||||
@@ -17,21 +17,72 @@ Gopeed(全稱 Go Speed),是一款使用`Golang`+`Flutter`編寫的高速
|
|||||||
|
|
||||||
前往 ✈ [主頁](https://gopeed.com/zh-CN) | 📖 [文檔](https://docs.gopeed.com/zh/)
|
前往 ✈ [主頁](https://gopeed.com/zh-CN) | 📖 [文檔](https://docs.gopeed.com/zh/)
|
||||||
|
|
||||||
## 安裝
|
## 下載
|
||||||
|
|
||||||
**已支援的平台**
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>運行平台</th>
|
||||||
|
<th>安裝包類型</th>
|
||||||
|
<th>下載鏈接</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=2>Windows</td>
|
||||||
|
<td><code>EXE Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable ZIP</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>MacOS</td>
|
||||||
|
<td><code>DMG Installer</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan=4>Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>DEB</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>AppImage</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-x86_64.AppImage">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Android</td>
|
||||||
|
<td><code>APK</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Web</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://github.com/GopeedLab/gopeed/releases/latest">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Docker</td>
|
||||||
|
<td></td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">前往</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
- [x] Windows
|
更多關於安裝的內容請參考[安裝文檔](https://docs.gopeed.com/zh/install.html)
|
||||||
- [x] MacOS
|
|
||||||
- [x] Linux
|
|
||||||
- [x] Android
|
|
||||||
- [x] iOS
|
|
||||||
- [x] Web
|
|
||||||
- [x] Docker
|
|
||||||
|
|
||||||
[下載](https://github.com/GopeedLab/gopeed/releases/latest)
|
|
||||||
|
|
||||||
> 註:MacOS 版運行時若提示損壞,請在終端中執行 `xattr -d com.apple.quarantine /Applications/Gopeed.app`
|
|
||||||
|
|
||||||
### 使用CLI安裝
|
### 使用CLI安裝
|
||||||
|
|
||||||
@@ -41,26 +92,6 @@ Gopeed(全稱 Go Speed),是一款使用`Golang`+`Flutter`編寫的高速
|
|||||||
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Docker
|
|
||||||
|
|
||||||
#### 直接執行
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/root/Downloads -v /path/to/storage:/app/storage liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
[更多關於 Docker 的使用](https://docs.gopeed.com/zh/install.html#docker-%E5%AE%89%E8%A3%85)
|
|
||||||
|
|
||||||
#### 使用 Docker Compose
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 訪問服務
|
|
||||||
|
|
||||||
當 docker 容器運作時,可以通過 `http://localhost:9999` 訪問 web 頁面。
|
|
||||||
|
|
||||||
## 贊助
|
## 贊助
|
||||||
|
|
||||||
如果你認為該項目對你有所幫助,請考慮[贊助](https://docs.gopeed.com/zh/donate)以支持該項目的持續發展,謝謝!
|
如果你認為該項目對你有所幫助,請考慮[贊助](https://docs.gopeed.com/zh/donate)以支持該項目的持續發展,謝謝!
|
||||||
@@ -77,8 +108,8 @@ docker-compose up -d
|
|||||||
|
|
||||||
### 開發環境
|
### 開發環境
|
||||||
|
|
||||||
1. Golang 1.19+
|
1. Golang 1.21+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.16+
|
||||||
|
|
||||||
### 克隆項目
|
### 克隆項目
|
||||||
|
|
||||||
@@ -137,7 +168,7 @@ gomobile init
|
|||||||
- android
|
- android
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
gomobile bind -tags nosqlite -ldflags="-w -s" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 19 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 309 KiB |
@@ -65,6 +65,9 @@ var (
|
|||||||
|
|
||||||
func printProgress(task *download.Task, title string) {
|
func printProgress(task *download.Task, title string) {
|
||||||
var rate float64
|
var rate float64
|
||||||
|
if task.Meta.Res == nil {
|
||||||
|
task = emptyTask
|
||||||
|
}
|
||||||
if task.Meta.Res.Size <= 0 {
|
if task.Meta.Res.Size <= 0 {
|
||||||
rate = 0
|
rate = 0
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest"
|
"github.com/GopeedLab/gopeed/pkg/rest"
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -24,14 +25,20 @@ func Start(cfg *model.StartConfig) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if downloadCfg.FirstLoad {
|
if downloadCfg.FirstLoad {
|
||||||
// Set default download dir to user download dir
|
// Set default download dir, in docker, it will be ${exe}/Downloads, else it will be ${user}/Downloads
|
||||||
|
var downloadDir string
|
||||||
|
if base.InDocker == "true" {
|
||||||
|
downloadDir = filepath.Join(filepath.Dir(cfg.StorageDir), "Downloads")
|
||||||
|
} else {
|
||||||
userDir, err := os.UserHomeDir()
|
userDir, err := os.UserHomeDir()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
downloadDir := filepath.Join(userDir, "Downloads")
|
downloadDir = filepath.Join(userDir, "Downloads")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if downloadDir != "" {
|
||||||
downloadCfg.DownloadDir = downloadDir
|
downloadCfg.DownloadDir = downloadDir
|
||||||
rest.Downloader.PutConfig(downloadCfg)
|
rest.Downloader.PutConfig(downloadCfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
fmt.Printf("Server start success on http://%s\n", listener.Addr().String())
|
fmt.Printf("Server start success on http://%s\n", listener.Addr().String())
|
||||||
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
|
if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type args struct {
|
|||||||
Username *string `json:"username"`
|
Username *string `json:"username"`
|
||||||
Password *string `json:"password"`
|
Password *string `json:"password"`
|
||||||
ApiToken *string `json:"apiToken"`
|
ApiToken *string `json:"apiToken"`
|
||||||
|
StorageDir *string `json:"storageDir"`
|
||||||
|
|
||||||
configPath *string
|
configPath *string
|
||||||
}
|
}
|
||||||
@@ -25,6 +26,7 @@ func parse() *args {
|
|||||||
cliArgs.Username = flag.String("u", "gopeed", "HTTP Basic Auth Username")
|
cliArgs.Username = flag.String("u", "gopeed", "HTTP Basic Auth Username")
|
||||||
cliArgs.Password = flag.String("p", "", "HTTP Basic Auth Pwd")
|
cliArgs.Password = flag.String("p", "", "HTTP Basic Auth Pwd")
|
||||||
cliArgs.ApiToken = flag.String("T", "", "API token, that can only be used when basic authentication is enabled.")
|
cliArgs.ApiToken = flag.String("T", "", "API token, that can only be used when basic authentication is enabled.")
|
||||||
|
cliArgs.StorageDir = flag.String("d", "", "Storage directory")
|
||||||
cliArgs.configPath = flag.String("c", "./config.json", "Config file path")
|
cliArgs.configPath = flag.String("c", "./config.json", "Config file path")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -45,6 +47,9 @@ func parse() *args {
|
|||||||
if cfgArgs.ApiToken == nil {
|
if cfgArgs.ApiToken == nil {
|
||||||
cfgArgs.ApiToken = cliArgs.ApiToken
|
cfgArgs.ApiToken = cliArgs.ApiToken
|
||||||
}
|
}
|
||||||
|
if cfgArgs.StorageDir == nil {
|
||||||
|
cfgArgs.StorageDir = cliArgs.StorageDir
|
||||||
|
}
|
||||||
return cfgArgs
|
return cfgArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,11 +31,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dir string
|
||||||
|
if args.StorageDir != nil && *args.StorageDir != "" {
|
||||||
|
dir = *args.StorageDir
|
||||||
|
} else {
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
dir := filepath.Dir(exe)
|
dir = filepath.Dir(exe)
|
||||||
|
}
|
||||||
|
|
||||||
cfg := &model.StartConfig{
|
cfg := &model.StartConfig{
|
||||||
Network: "tcp",
|
Network: "tcp",
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
chown -R ${PUID}:${PGID} /app
|
||||||
|
|
||||||
|
umask ${UMASK}
|
||||||
|
|
||||||
|
exec su-exec ${PUID}:${PGID} ./gopeed "$@"
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
module github.com/GopeedLab/gopeed
|
module github.com/GopeedLab/gopeed
|
||||||
|
|
||||||
go 1.19
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.2-0.20230527121029-a582b4f397b9
|
github.com/anacrolix/missinggo/v2 v2.7.3
|
||||||
github.com/anacrolix/torrent v1.52.5
|
github.com/anacrolix/torrent v1.53.3
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||||
github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d
|
github.com/dop251/goja v0.0.0-20231027120936-b396bb4c349d
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c
|
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c
|
||||||
@@ -12,97 +12,107 @@ require (
|
|||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0
|
github.com/matoous/go-nanoid/v2 v2.0.0
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rs/zerolog v1.31.0
|
github.com/rs/zerolog v1.31.0
|
||||||
github.com/virtuald/go-paniclog v0.0.0-20190812204905-43a7fa316459
|
github.com/virtuald/go-paniclog v0.0.0-20190812204905-43a7fa316459
|
||||||
go.etcd.io/bbolt v1.3.8
|
go.etcd.io/bbolt v1.3.8
|
||||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
|
||||||
golang.org/x/sync v0.3.0
|
golang.org/x/sync v0.6.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
crawshaw.io/sqlite v0.3.3-0.20220618202545-d1964889ea3c // indirect
|
|
||||||
dario.cat/mergo v1.0.0 // indirect
|
dario.cat/mergo v1.0.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
|
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
|
||||||
github.com/RoaringBitmap/roaring v1.2.3 // indirect
|
github.com/RoaringBitmap/roaring v1.7.0 // indirect
|
||||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||||
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
|
github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect
|
||||||
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
github.com/alecthomas/atomic v0.1.0-alpha2 // indirect
|
||||||
github.com/anacrolix/chansync v0.3.0 // indirect
|
github.com/anacrolix/chansync v0.4.0 // indirect
|
||||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 // indirect
|
github.com/anacrolix/dht/v2 v2.21.0 // indirect
|
||||||
github.com/anacrolix/envpprof v1.2.1 // indirect
|
github.com/anacrolix/envpprof v1.3.0 // indirect
|
||||||
github.com/anacrolix/generics v0.0.0-20230428105757-683593396d68 // indirect
|
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 // indirect
|
||||||
github.com/anacrolix/go-libutp v1.3.1 // indirect
|
github.com/anacrolix/go-libutp v1.3.1 // indirect
|
||||||
github.com/anacrolix/log v0.14.0 // indirect
|
github.com/anacrolix/log v0.14.6-0.20231202035202-ed7a02cad0b4 // indirect
|
||||||
github.com/anacrolix/missinggo v1.3.0 // indirect
|
github.com/anacrolix/missinggo v1.3.0 // indirect
|
||||||
github.com/anacrolix/missinggo/perf v1.0.0 // indirect
|
github.com/anacrolix/missinggo/perf v1.0.0 // indirect
|
||||||
github.com/anacrolix/mmsg v1.0.0 // indirect
|
github.com/anacrolix/mmsg v1.0.0 // indirect
|
||||||
github.com/anacrolix/multiless v0.3.0 // indirect
|
github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 // indirect
|
||||||
github.com/anacrolix/stm v0.4.0 // indirect
|
github.com/anacrolix/stm v0.5.0 // indirect
|
||||||
github.com/anacrolix/sync v0.4.0 // indirect
|
github.com/anacrolix/sync v0.5.1 // indirect
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect
|
github.com/anacrolix/upnp v0.1.3 // indirect
|
||||||
github.com/anacrolix/utp v0.1.0 // indirect
|
github.com/anacrolix/utp v0.2.0 // indirect
|
||||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
github.com/benbjohnson/immutable v0.3.0 // indirect
|
github.com/benbjohnson/immutable v0.4.3 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.2.2 // indirect
|
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
|
||||||
github.com/cloudflare/circl v1.3.3 // indirect
|
github.com/cloudflare/circl v1.3.3 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||||
github.com/emirpasic/gods v1.18.1 // indirect
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-llsqlite/adapter v0.1.0 // indirect
|
||||||
|
github.com/go-llsqlite/crawshaw v0.5.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.1 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.1 // indirect
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/huandu/xstrings v1.4.0 // indirect
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/lispad/go-generics-tools v1.1.0 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-ieproxy v0.0.11 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mschoch/smat v0.2.0 // indirect
|
github.com/mschoch/smat v0.2.0 // indirect
|
||||||
github.com/pion/datachannel v1.5.2 // indirect
|
github.com/pion/datachannel v1.5.5 // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.4 // indirect
|
github.com/pion/dtls/v2 v2.2.9 // indirect
|
||||||
github.com/pion/ice/v2 v2.2.6 // indirect
|
github.com/pion/ice/v2 v2.3.12 // indirect
|
||||||
github.com/pion/interceptor v0.1.11 // indirect
|
github.com/pion/interceptor v0.1.25 // indirect
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
github.com/pion/mdns v0.0.5 // indirect
|
github.com/pion/mdns v0.0.9 // indirect
|
||||||
github.com/pion/randutil v0.1.0 // indirect
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
github.com/pion/rtcp v1.2.9 // indirect
|
github.com/pion/rtcp v1.2.13 // indirect
|
||||||
github.com/pion/rtp v1.7.13 // indirect
|
github.com/pion/rtp v1.8.3 // indirect
|
||||||
github.com/pion/sctp v1.8.2 // indirect
|
github.com/pion/sctp v1.8.9 // indirect
|
||||||
github.com/pion/sdp/v3 v3.0.5 // indirect
|
github.com/pion/sdp/v3 v3.0.6 // indirect
|
||||||
github.com/pion/srtp/v2 v2.0.9 // indirect
|
github.com/pion/srtp/v2 v2.0.18 // indirect
|
||||||
github.com/pion/stun v0.3.5 // indirect
|
github.com/pion/stun v0.6.1 // indirect
|
||||||
github.com/pion/transport v0.13.1 // indirect
|
github.com/pion/transport/v2 v2.2.4 // indirect
|
||||||
github.com/pion/transport/v2 v2.0.0 // indirect
|
github.com/pion/turn/v2 v2.1.4 // indirect
|
||||||
github.com/pion/turn/v2 v2.0.8 // indirect
|
github.com/pion/webrtc/v3 v3.2.24 // indirect
|
||||||
github.com/pion/udp v0.1.4 // indirect
|
|
||||||
github.com/pion/webrtc/v3 v3.1.42 // indirect
|
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 // indirect
|
||||||
github.com/sergi/go-diff v1.1.0 // indirect
|
github.com/sergi/go-diff v1.1.0 // indirect
|
||||||
github.com/skeema/knownhosts v1.2.0 // indirect
|
github.com/skeema/knownhosts v1.2.0 // indirect
|
||||||
github.com/tidwall/btree v1.6.0 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
|
github.com/tidwall/btree v1.7.0 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
go.opentelemetry.io/otel v1.8.0 // indirect
|
github.com/xiaoqidun/setft v0.0.0-20220310121541-be86327699ad // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.8.0 // indirect
|
go.opentelemetry.io/otel v1.22.0 // indirect
|
||||||
golang.org/x/crypto v0.14.0 // indirect
|
go.opentelemetry.io/otel/metric v1.22.0 // indirect
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
go.opentelemetry.io/otel/trace v1.22.0 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/crypto v0.18.0 // indirect
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
golang.org/x/mod v0.14.0 // indirect
|
||||||
|
golang.org/x/net v0.20.0 // indirect
|
||||||
|
golang.org/x/sys v0.16.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
golang.org/x/time v0.5.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.17.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
modernc.org/libc v1.40.6 // indirect
|
||||||
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
modernc.org/memory v1.7.2 // indirect
|
||||||
|
modernc.org/sqlite v1.28.0 // indirect
|
||||||
|
zombiezen.com/go/sqlite v1.1.0 // indirect
|
||||||
)
|
)
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797 h1:yDf7ARQc637HoxDho7xjqdvO5ZA2Yb+xzv/fOnnvZzw=
|
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
||||||
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
||||||
crawshaw.io/sqlite v0.3.3-0.20220618202545-d1964889ea3c h1:wvzox0eLO6CKQAMcOqz7oH3UFqMpMmK7kwmwV+22HIs=
|
|
||||||
crawshaw.io/sqlite v0.3.3-0.20220618202545-d1964889ea3c/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
|
||||||
@@ -17,8 +14,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjA
|
|||||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||||
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI=
|
||||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY=
|
github.com/RoaringBitmap/roaring v1.7.0 h1:OZF303tJCER1Tj3x+aArx/S5X7hrT186ri6JjrGvG68=
|
||||||
github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
|
github.com/RoaringBitmap/roaring v1.7.0/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||||
@@ -33,25 +30,26 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
|||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U=
|
github.com/anacrolix/chansync v0.4.0 h1:Md0HM7zYCAO4KwNwgcIRgxNsMxiRuk7D1Ha0Uo+2y60=
|
||||||
github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
github.com/anacrolix/chansync v0.4.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k=
|
||||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 h1:8V0K09lrGoeT2KRJNOtspA7q+OMxGwQqK/Ug0IiaaRE=
|
github.com/anacrolix/dht/v2 v2.21.0 h1:8nzI+faaynY9jOKmVgdmBZVrTo8B7ZE/LKEgN3Vl/Bs=
|
||||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444/go.mod h1:MctKM1HS5YYDb3F30NGJxLE+QPuqWoT5ReW/4jt8xew=
|
github.com/anacrolix/dht/v2 v2.21.0/go.mod h1:SDGC+sEs1pnO2sJGYuhvIis7T8749dDHNfcjtdH4e3g=
|
||||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||||
github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
|
||||||
github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
||||||
github.com/anacrolix/envpprof v1.2.1 h1:25TJe6t/i0AfzzldiGFKCpD+s+dk8lONBcacJZB2rdE=
|
github.com/anacrolix/envpprof v1.3.0 h1:WJt9bpuT7A/CDCxPOv/eeZqHWlle/Y0keJUvc6tcJDk=
|
||||||
github.com/anacrolix/envpprof v1.2.1/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4=
|
github.com/anacrolix/envpprof v1.3.0/go.mod h1:7QIG4CaX1uexQ3tqd5+BRa/9e2D02Wcertl6Yh0jCB0=
|
||||||
github.com/anacrolix/generics v0.0.0-20230428105757-683593396d68 h1:fyXlBfnlFzZSFckJ8QLb2lfmWfY++4RiUnae7ZMuv0A=
|
github.com/anacrolix/generics v0.0.0-20230113004304-d6428d516633/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
||||||
github.com/anacrolix/generics v0.0.0-20230428105757-683593396d68/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13 h1:qwOprPTDMM3BASJRf84mmZnTXRsPGGJ8xoHKQS7m3so=
|
||||||
|
github.com/anacrolix/generics v0.0.0-20230911070922-5dd7545c6b13/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8=
|
||||||
github.com/anacrolix/go-libutp v1.3.1 h1:idJzreNLl+hNjGC3ZnUOjujEaryeOGgkwHLqSGoige0=
|
github.com/anacrolix/go-libutp v1.3.1 h1:idJzreNLl+hNjGC3ZnUOjujEaryeOGgkwHLqSGoige0=
|
||||||
github.com/anacrolix/go-libutp v1.3.1/go.mod h1:heF41EC8kN0qCLMokLBVkB8NXiLwx3t8R8810MTNI5o=
|
github.com/anacrolix/go-libutp v1.3.1/go.mod h1:heF41EC8kN0qCLMokLBVkB8NXiLwx3t8R8810MTNI5o=
|
||||||
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||||
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU=
|
||||||
github.com/anacrolix/log v0.10.1-0.20220123034749-3920702c17f8/go.mod h1:GmnE2c0nvz8pOIPUSC9Rawgefy1sDXqposC2wgtBZE4=
|
|
||||||
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
|
github.com/anacrolix/log v0.13.1/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68=
|
||||||
github.com/anacrolix/log v0.14.0 h1:mYhTSemILe/Z8tIxbGdTIWWpPspI8W/fhZHpoFbDaL0=
|
github.com/anacrolix/log v0.14.2/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
||||||
github.com/anacrolix/log v0.14.0/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
github.com/anacrolix/log v0.14.6-0.20231202035202-ed7a02cad0b4 h1:CdVK9IoqoqklXQQ4+L2aew64xsz14KdOD+rnKdTQajg=
|
||||||
|
github.com/anacrolix/log v0.14.6-0.20231202035202-ed7a02cad0b4/go.mod h1:1OmJESOtxQGNMlUO5rcv96Vpp9mfMqXXbe2RdinFLdY=
|
||||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM=
|
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM=
|
||||||
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
|
github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM=
|
||||||
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s=
|
||||||
@@ -64,30 +62,29 @@ github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy
|
|||||||
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
||||||
github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY=
|
github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY=
|
||||||
github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA=
|
github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA=
|
||||||
github.com/anacrolix/missinggo/v2 v2.5.2/go.mod h1:yNvsLrtZYRYCOI+KRH/JM8TodHjtIE/bjOGhQaLOWIE=
|
github.com/anacrolix/missinggo/v2 v2.7.3 h1:Ee//CmZBMadeNiYB/hHo9ly2PFOEZ4Fhsbnug3rDAIE=
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.2-0.20230527121029-a582b4f397b9 h1:W/oGeHhYwxueeiDjQfmK9G+X9M2xJgfTtow62v0TWAs=
|
github.com/anacrolix/missinggo/v2 v2.7.3/go.mod h1:mIEtp9pgaXqt8VQ3NQxFOod/eQ1H0D1XsZzKUQfwtac=
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.2-0.20230527121029-a582b4f397b9/go.mod h1:mIEtp9pgaXqt8VQ3NQxFOod/eQ1H0D1XsZzKUQfwtac=
|
|
||||||
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw=
|
github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw=
|
||||||
github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg=
|
github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg=
|
||||||
github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc=
|
github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc=
|
||||||
github.com/anacrolix/multiless v0.3.0 h1:5Bu0DZncjE4e06b9r1Ap2tUY4Au0NToBP5RpuEngSis=
|
github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7 h1:lOtCD+LzoD1g7bowhYJNR++uV+FyY5bTZXKwnPex9S8=
|
||||||
github.com/anacrolix/multiless v0.3.0/go.mod h1:TrCLEZfIDbMVfLoQt5tOoiBS/uq4y8+ojuEVVvTNPX4=
|
github.com/anacrolix/multiless v0.3.1-0.20221221005021-2d12701f83f7/go.mod h1:zJv1JF9AqdZiHwxqPgjuOZDGWER6nyE48WBCi/OOrMM=
|
||||||
github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg=
|
github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg=
|
||||||
github.com/anacrolix/stm v0.4.0 h1:tOGvuFwaBjeu1u9X1eIh9TX8OEedEiEQ1se1FjhFnXY=
|
github.com/anacrolix/stm v0.5.0 h1:9df1KBpttF0TzLgDq51Z+TEabZKMythqgx89f1FQJt8=
|
||||||
github.com/anacrolix/stm v0.4.0/go.mod h1:GCkwqWoAsP7RfLW+jw+Z0ovrt2OO7wRzcTtFYMYY5t8=
|
github.com/anacrolix/stm v0.5.0/go.mod h1:MOwrSy+jCm8Y7HYfMAwPj7qWVu7XoVvjOiYwJmpeB/M=
|
||||||
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
|
github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk=
|
||||||
github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
||||||
github.com/anacrolix/sync v0.4.0 h1:T+MdO/u87ir/ijWsTFsPYw5jVm0SMm4kVpg8t4KF38o=
|
github.com/anacrolix/sync v0.5.1 h1:FbGju6GqSjzVoTgcXTUKkF041lnZkG5P0C3T5RL3SGc=
|
||||||
github.com/anacrolix/sync v0.4.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
github.com/anacrolix/sync v0.5.1/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g=
|
||||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||||
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||||
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8=
|
||||||
github.com/anacrolix/torrent v1.52.5 h1:jWowdx+EU6zFVfBwmnL0d3H4J6vTFEGOrHI35YdfIT8=
|
github.com/anacrolix/torrent v1.53.3 h1:Abb3J8p/JWUjOzHaii8kixuDOGMXz+Oh8+hwc/zA2lA=
|
||||||
github.com/anacrolix/torrent v1.52.5/go.mod h1:CcM8oPMYye5J42cSqJrmUpqwRFgSsJQ1jCEHwygqnqQ=
|
github.com/anacrolix/torrent v1.53.3/go.mod h1:is8GNob5qDeZ5Kq+pKPiE2xqYUi1ms7IgSB+CftZETk=
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 h1:QAVZ3pN/J4/UziniAhJR2OZ9Ox5kOY2053tBbbqUPYA=
|
github.com/anacrolix/upnp v0.1.3 h1:NlYEhE75adz2npEJKjbqyqnyW9qU4STookvSNXBJ5ao=
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96/go.mod h1:Wa6n8cYIdaG35x15aH3Zy6d03f7P728QfdcDeD/IEOs=
|
github.com/anacrolix/upnp v0.1.3/go.mod h1:Qyhbqo69gwNWvEk1xNTXsS5j7hMHef9hdr984+9fIic=
|
||||||
github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4=
|
github.com/anacrolix/utp v0.2.0 h1:65Cdmr6q9WSw2KsM+rtJFu7rqDzLl2bdysf4KlNPcFI=
|
||||||
github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk=
|
github.com/anacrolix/utp v0.2.0/go.mod h1:HGk4GYQw1O/3T1+yhqT/F6EcBd+AAwlo9dYErNy7mj8=
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
@@ -95,14 +92,14 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
|
|||||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
||||||
github.com/benbjohnson/immutable v0.3.0 h1:TVRhuZx2wG9SZ0LRdqlbs9S5BZ6Y24hJEHTCgWHZEIw=
|
github.com/benbjohnson/immutable v0.4.3 h1:GYHcksoJ9K6HyAUpGxwZURrbTkXA0Dh4otXGqbhdrjA=
|
||||||
github.com/benbjohnson/immutable v0.3.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
|
github.com/benbjohnson/immutable v0.4.3/go.mod h1:qJIKKSmdqz1tVzNtst1DZzvaqOU1onk1rc03IeM3Owk=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk=
|
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||||
github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||||
@@ -133,8 +130,9 @@ github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8
|
|||||||
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c h1:hLoodLRD4KLWIH8eyAQCLcH8EqIrjac7fCkp/fHnvuQ=
|
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c h1:hLoodLRD4KLWIH8eyAQCLcH8EqIrjac7fCkp/fHnvuQ=
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c/go.mod h1:bhGPmCgCCTSRfiMYWjpS46IDo9EUZXlsuUaPXSWGbv0=
|
github.com/dop251/goja_nodejs v0.0.0-20231122114759-e84d9a924c5c/go.mod h1:bhGPmCgCCTSRfiMYWjpS46IDo9EUZXlsuUaPXSWGbv0=
|
||||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
@@ -146,7 +144,8 @@ github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM
|
|||||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||||
@@ -165,11 +164,15 @@ github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+
|
|||||||
github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo=
|
github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-llsqlite/adapter v0.1.0 h1:wGSQNsu/rtYeu/lqZNZQMjwUdEF3OW66xTLvsFwJQUw=
|
||||||
|
github.com/go-llsqlite/adapter v0.1.0/go.mod h1:DADrR88ONKPPeSGjFp5iEN55Arx3fi2qXZeKCYDpbmU=
|
||||||
|
github.com/go-llsqlite/crawshaw v0.5.0 h1:Olbqkth53vkkh4WvmkYjrtfOBcxXD3rMYBYuk6FNH3E=
|
||||||
|
github.com/go-llsqlite/crawshaw v0.5.0/go.mod h1:/YJdV7uBQaYDE0fwe4z3wwJIZBJxdYzd38ICggWqtaE=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
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-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
|
||||||
@@ -207,13 +210,15 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
|||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
|
||||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
|
||||||
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
|
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
@@ -224,8 +229,8 @@ github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv
|
|||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
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 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
@@ -233,8 +238,8 @@ github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbc
|
|||||||
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
|
||||||
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
|
||||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
@@ -253,12 +258,11 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn
|
|||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lispad/go-generics-tools v1.1.0 h1:mbSgcxdFVmpoyso1X/MJHXbSbSL3dD+qhRryyxk+/XY=
|
|
||||||
github.com/lispad/go-generics-tools v1.1.0/go.mod h1:2csd1EJljo/gy5qG4khXol7ivCPptNjG5Uv2X8MgK84=
|
|
||||||
github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
|
github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U=
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0=
|
github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0=
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g=
|
github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g=
|
||||||
@@ -266,9 +270,12 @@ github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
|||||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-ieproxy v0.0.11 h1:MQ/5BuGSgDAHZOJe6YY80IF2UVCfGkwfo6AeD7HtHYo=
|
||||||
|
github.com/mattn/go-ieproxy v0.0.11/go.mod h1:/NsJd+kxZBmjMc5hrJCKMbP57B84rvq9BiDRbtO9AS0=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -293,49 +300,54 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
|
|||||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
|
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
|
||||||
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
|
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
|
||||||
github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
|
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||||
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
|
github.com/pion/dtls/v2 v2.2.9 h1:K+D/aVf9/REahQvqk6G5JavdrD8W1PWDKC11UlwN7ts=
|
||||||
github.com/pion/dtls/v2 v2.2.4 h1:YSfYwDQgrxMYXLBc/m7PFY5BVtWlNm/DN4qoU2CbcWg=
|
github.com/pion/dtls/v2 v2.2.9/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||||
github.com/pion/dtls/v2 v2.2.4/go.mod h1:WGKfxqhrddne4Kg3p11FUMJrynkOY4lb25zHNO49wuw=
|
github.com/pion/ice/v2 v2.3.11/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E=
|
||||||
github.com/pion/ice/v2 v2.2.6 h1:R/vaLlI1J2gCx141L5PEwtuGAGcyS6e7E0hDeJFq5Ig=
|
github.com/pion/ice/v2 v2.3.12 h1:NWKW2b3+oSZS3klbQMIEWQ0i52Kuo0KBg505a5kQv4s=
|
||||||
github.com/pion/ice/v2 v2.2.6/go.mod h1:SWuHiOGP17lGromHTFadUe1EuPgFh/oCU6FCMZHooVE=
|
github.com/pion/ice/v2 v2.3.12/go.mod h1:hPcLC3kxMa+JGRzMHqQzjoSj3xtE9F+eoncmXLlCL4E=
|
||||||
github.com/pion/interceptor v0.1.11 h1:00U6OlqxA3FFB50HSg25J/8cWi7P6FbSzw4eFn24Bvs=
|
github.com/pion/interceptor v0.1.25 h1:pwY9r7P6ToQ3+IF0bajN0xmk/fNw/suTgaTdlwTDmhc=
|
||||||
github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8=
|
github.com/pion/interceptor v0.1.25/go.mod h1:wkbPYAak5zKsfpVDYMtEfWEy8D4zL+rpxCxPImLOg3Y=
|
||||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||||
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
|
github.com/pion/mdns v0.0.8/go.mod h1:hYE72WX8WDveIhg7fmXgMKivD3Puklk0Ymzog0lSyaI=
|
||||||
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
|
github.com/pion/mdns v0.0.9 h1:7Ue5KZsqq8EuqStnpPWV33vYYEH0+skdDN5L7EiEsI4=
|
||||||
|
github.com/pion/mdns v0.0.9/go.mod h1:2JA5exfxwzXiCihmxpTKgFUpiQws2MnipoPK09vecIc=
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||||
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
|
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
|
||||||
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
|
github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||||
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
|
github.com/pion/rtcp v1.2.13 h1:+EQijuisKwm/8VBs8nWllr0bIndR7Lf7cZG200mpbNo=
|
||||||
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
github.com/pion/rtcp v1.2.13/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4=
|
||||||
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
github.com/pion/rtp v1.8.2/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||||
github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA=
|
github.com/pion/rtp v1.8.3 h1:VEHxqzSVQxCkKDSHro5/4IUUG1ea+MFdqR2R3xSpNU8=
|
||||||
github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU=
|
||||||
github.com/pion/sdp/v3 v3.0.5 h1:ouvI7IgGl+V4CrqskVtr3AaTrPvPisEOxwgpdktctkU=
|
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
|
||||||
github.com/pion/sdp/v3 v3.0.5/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
|
github.com/pion/sctp v1.8.8/go.mod h1:igF9nZBrjh5AtmKc7U30jXltsFHicFCXSmWA2GWRaWs=
|
||||||
github.com/pion/srtp/v2 v2.0.9 h1:JJq3jClmDFBPX/F5roEb0U19jSU7eUhyDqR/NZ34EKQ=
|
github.com/pion/sctp v1.8.9 h1:TP5ZVxV5J7rz7uZmbyvnUvsn7EJ2x/5q9uhsTtXbI3g=
|
||||||
github.com/pion/srtp/v2 v2.0.9/go.mod h1:5TtM9yw6lsH0ppNCehB/EjEUli7VkUgKSPJqWVqbhQ4=
|
github.com/pion/sctp v1.8.9/go.mod h1:cMLT45jqw3+jiJCrtHVwfQLnfR0MGZ4rgOJwUOIqLkI=
|
||||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
|
||||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
|
||||||
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo=
|
||||||
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
|
github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
|
||||||
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
|
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||||
github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA=
|
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||||
github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg=
|
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
|
||||||
github.com/pion/transport/v2 v2.0.0 h1:bsMYyqHCbkvHwj+eNCFBuxtlKndKfyGI2vaQmM3fIE4=
|
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
|
||||||
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
|
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||||
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
|
github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc=
|
||||||
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
|
github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||||
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
|
github.com/pion/transport/v2 v2.2.4 h1:41JJK6DZQYSeVLxILA2+F4ZkKb4Xd/tFJZRFZQ9QAlo=
|
||||||
github.com/pion/udp v0.1.4 h1:OowsTmu1Od3sD6i3fQUJxJn2fEvJO6L1TidgadtbTI8=
|
github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0=
|
||||||
github.com/pion/udp v0.1.4/go.mod h1:G8LDo56HsFwC24LIcnT4YIDU5qcB6NepqqjP0keL2us=
|
github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM=
|
||||||
github.com/pion/webrtc/v3 v3.1.42 h1:wJEQFIXVanptnQcHOLTuIo4AtGB2+mG2x4OhIhnITOA=
|
github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0=
|
||||||
github.com/pion/webrtc/v3 v3.1.42/go.mod h1:ffD9DulDrPxyWvDPUIPAOSAWx9GUlOExiJPf7cCcMLA=
|
github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||||
|
github.com/pion/turn/v2 v2.1.4 h1:2xn8rduI5W6sCZQkEnIUDAkrBQNl2eYIBCHMZ3QMmP8=
|
||||||
|
github.com/pion/turn/v2 v2.1.4/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
|
||||||
|
github.com/pion/webrtc/v3 v3.2.24 h1:MiFL5DMo2bDaaIFWr0DDpwiV/L4EGbLZb+xoRvfEo1Y=
|
||||||
|
github.com/pion/webrtc/v3 v3.2.24/go.mod h1:1CaT2fcZzZ6VZA+O1i9yK2DU4EOcXVvSbWG9pr5jefs=
|
||||||
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||||
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
@@ -362,11 +374,14 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
|
|||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8=
|
||||||
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
|
||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
||||||
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
@@ -397,10 +412,12 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/tidwall/btree v1.6.0 h1:LDZfKfQIBHGHWSwckhXI0RPSXzlo+KYdjK7FWSqOzzg=
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
|
||||||
|
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
|
||||||
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
@@ -410,42 +427,52 @@ github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPyS
|
|||||||
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
|
github.com/xiaoqidun/setft v0.0.0-20220310121541-be86327699ad h1:QtuWk6dsrNXc/ugwCBEN0jG52q/4tXRzMvZm4fH6T9g=
|
||||||
|
github.com/xiaoqidun/setft v0.0.0-20220310121541-be86327699ad/go.mod h1:Jj8p9bgKGTPQ+M8CdUMS9p7Mmdoxa3OAcAjJQBu0CcI=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
|
||||||
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opentelemetry.io/otel v1.8.0 h1:zcvBFizPbpa1q7FehvFiHbQwGzmPILebO0tyqIR5Djg=
|
go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y=
|
||||||
go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM=
|
go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI=
|
||||||
go.opentelemetry.io/otel/trace v1.8.0 h1:cSy0DF9eGI5WIfNwZ1q2iUyGj00tGzP24dE1lOlHrfY=
|
go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg=
|
||||||
go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4=
|
go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY=
|
||||||
|
go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0=
|
||||||
|
go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
|
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||||
|
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d h1:vtUKgx8dahOomfFzLREU8nSv25YHnTgLBn4rDnWZdU0=
|
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||||
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||||
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -459,25 +486,24 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||||
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
|
||||||
golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
|
||||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
|
||||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||||
|
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||||
|
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -487,10 +513,11 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -514,30 +541,38 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||||
|
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||||
|
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -545,13 +580,17 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -560,9 +599,11 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
|||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||||
|
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -607,3 +648,13 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
modernc.org/libc v1.40.6 h1:141JHq3SjhOOCjECBgD4K8VgTFOy19CnHwroC08DAig=
|
||||||
|
modernc.org/libc v1.40.6/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
||||||
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
|
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
||||||
|
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||||
|
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
|
||||||
|
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||||
|
zombiezen.com/go/sqlite v1.1.0 h1:2BIABTFCE221++xR90rV0mE6T5gFF8o0MUcKDNUrIVc=
|
||||||
|
zombiezen.com/go/sqlite v1.1.0/go.mod h1:rZEFEJSoeXeiwuAb6HugOJLhtDabl+EekT92DCEKOb0=
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
GetConfig func(v any) bool
|
GetConfig func(v any) bool
|
||||||
ProxyUrl *url.URL
|
ProxyConfig *base.DownloaderProxyConfig
|
||||||
FileController
|
FileController
|
||||||
//ContextDialer() (proxy.Dialer, error)
|
//ContextDialer() (proxy.Dialer, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package bt
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"github.com/GopeedLab/gopeed/internal/controller"
|
"github.com/GopeedLab/gopeed/internal/controller"
|
||||||
"github.com/GopeedLab/gopeed/internal/fetcher"
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
@@ -9,8 +10,8 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
"github.com/GopeedLab/gopeed/pkg/util"
|
||||||
"github.com/anacrolix/torrent"
|
"github.com/anacrolix/torrent"
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
"net/http"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -31,6 +32,7 @@ type Fetcher struct {
|
|||||||
meta *fetcher.FetcherMeta
|
meta *fetcher.FetcherMeta
|
||||||
|
|
||||||
torrentReady atomic.Bool
|
torrentReady atomic.Bool
|
||||||
|
torrentDrop atomic.Bool
|
||||||
create atomic.Bool
|
create atomic.Bool
|
||||||
progress fetcher.Progress
|
progress fetcher.Progress
|
||||||
}
|
}
|
||||||
@@ -63,10 +65,10 @@ func (f *Fetcher) initClient() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg := torrent.NewDefaultClientConfig()
|
cfg := torrent.NewDefaultClientConfig()
|
||||||
|
cfg.Bep20 = fmt.Sprintf("-GP%s-", parseBep20())
|
||||||
|
cfg.ExtendedHandshakeClientVersion = fmt.Sprintf("Gopeed %s", base.Version)
|
||||||
cfg.ListenPort = f.config.ListenPort
|
cfg.ListenPort = f.config.ListenPort
|
||||||
if f.ctl.ProxyUrl != nil {
|
cfg.HTTPProxy = f.ctl.ProxyConfig.ToHandler()
|
||||||
cfg.HTTPProxy = http.ProxyURL(f.ctl.ProxyUrl)
|
|
||||||
}
|
|
||||||
cfg.DefaultStorage = newFileOpts(newFileClientOpts{
|
cfg.DefaultStorage = newFileOpts(newFileClientOpts{
|
||||||
ClientBaseDir: cfg.DataDir,
|
ClientBaseDir: cfg.DataDir,
|
||||||
HandleFileTorrent: func(infoHash metainfo.Hash, ft *fileTorrentImpl) {
|
HandleFileTorrent: func(infoHash metainfo.Hash, ft *fileTorrentImpl) {
|
||||||
@@ -139,6 +141,7 @@ func (f *Fetcher) Pause() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fetcher) Close() (err error) {
|
func (f *Fetcher) Close() (err error) {
|
||||||
|
f.torrentDrop.Store(false)
|
||||||
f.safeDrop()
|
f.safeDrop()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -154,6 +157,9 @@ func (f *Fetcher) safeDrop() {
|
|||||||
|
|
||||||
func (f *Fetcher) Wait() (err error) {
|
func (f *Fetcher) Wait() (err error) {
|
||||||
for {
|
for {
|
||||||
|
if f.torrentDrop.Load() {
|
||||||
|
break
|
||||||
|
}
|
||||||
if f.torrentReady.Load() && len(f.meta.Opts.SelectFiles) > 0 {
|
if f.torrentReady.Load() && len(f.meta.Opts.SelectFiles) > 0 {
|
||||||
done := true
|
done := true
|
||||||
for _, selectIndex := range f.meta.Opts.SelectFiles {
|
for _, selectIndex := range f.meta.Opts.SelectFiles {
|
||||||
@@ -218,6 +224,7 @@ func (f *Fetcher) updateRes() {
|
|||||||
Files: make([]*base.FileInfo, len(f.torrent.Files())),
|
Files: make([]*base.FileInfo, len(f.torrent.Files())),
|
||||||
Hash: f.torrent.InfoHash().String(),
|
Hash: f.torrent.InfoHash().String(),
|
||||||
}
|
}
|
||||||
|
f.torrent.PeerConns()
|
||||||
for i, file := range f.torrent.Files() {
|
for i, file := range f.torrent.Files() {
|
||||||
res.Files[i] = &base.FileInfo{
|
res.Files[i] = &base.FileInfo{
|
||||||
Name: filepath.Base(file.DisplayPath()),
|
Name: filepath.Base(file.DisplayPath()),
|
||||||
@@ -306,3 +313,12 @@ func (fb *FetcherBuilder) Restore() (v any, f func(meta *fetcher.FetcherMeta, v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse version to bep20 format, fixed length 4, if not enough, fill 0
|
||||||
|
func parseBep20() string {
|
||||||
|
s := strings.ReplaceAll(base.Version, ".", "")
|
||||||
|
if len(s) < 4 {
|
||||||
|
s += strings.Repeat("0", 4-len(s))
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
@@ -8,8 +8,6 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/internal/test"
|
"github.com/GopeedLab/gopeed/internal/test"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/bt"
|
"github.com/GopeedLab/gopeed/pkg/protocol/bt"
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -60,7 +58,14 @@ func TestFetcher_ResolveWithProxy(t *testing.T) {
|
|||||||
proxyListener := test.StartSocks5Server(usr, pwd)
|
proxyListener := test.StartSocks5Server(usr, pwd)
|
||||||
defer proxyListener.Close()
|
defer proxyListener.Close()
|
||||||
|
|
||||||
doResolve(t, buildConfigFetcher(util.BuildProxyUrl("socks5", proxyListener.Addr().String(), usr, pwd)))
|
doResolve(t, buildConfigFetcher(&base.DownloaderProxyConfig{
|
||||||
|
Enable: true,
|
||||||
|
System: false,
|
||||||
|
Scheme: "socks5",
|
||||||
|
Host: proxyListener.Addr().String(),
|
||||||
|
Usr: usr,
|
||||||
|
Pwd: pwd,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func doResolve(t *testing.T, fetcher fetcher.Fetcher) {
|
func doResolve(t *testing.T, fetcher fetcher.Fetcher) {
|
||||||
@@ -100,7 +105,7 @@ func buildFetcher() fetcher.Fetcher {
|
|||||||
return fetcher
|
return fetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConfigFetcher(proxyUrl *url.URL) fetcher.Fetcher {
|
func buildConfigFetcher(proxyConfig *base.DownloaderProxyConfig) fetcher.Fetcher {
|
||||||
fetcher := new(FetcherBuilder).Build()
|
fetcher := new(FetcherBuilder).Build()
|
||||||
newController := controller.NewController()
|
newController := controller.NewController()
|
||||||
mockCfg := config{
|
mockCfg := config{
|
||||||
@@ -114,7 +119,7 @@ func buildConfigFetcher(proxyUrl *url.URL) fetcher.Fetcher {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
newController.ProxyUrl = proxyUrl
|
newController.ProxyConfig = proxyConfig
|
||||||
fetcher.Setup(newController)
|
fetcher.Setup(newController)
|
||||||
return fetcher
|
return fetcher
|
||||||
}
|
}
|
||||||
@@ -3,4 +3,5 @@ package http
|
|||||||
type config struct {
|
type config struct {
|
||||||
UserAgent string `json:"userAgent"`
|
UserAgent string `json:"userAgent"`
|
||||||
Connections int `json:"connections"`
|
Connections int `json:"connections"`
|
||||||
|
UseServerCtime bool `json:"useServerCtime"`
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/internal/fetcher"
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
fhttp "github.com/GopeedLab/gopeed/pkg/protocol/http"
|
fhttp "github.com/GopeedLab/gopeed/pkg/protocol/http"
|
||||||
|
"github.com/xiaoqidun/setft"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
@@ -105,6 +106,7 @@ func (f *Fetcher) Resolve(req *base.Request) error {
|
|||||||
Range: false,
|
Range: false,
|
||||||
Files: []*base.FileInfo{},
|
Files: []*base.FileInfo{},
|
||||||
}
|
}
|
||||||
|
|
||||||
if base.HttpCodePartialContent == httpResp.StatusCode || (base.HttpCodeOK == httpResp.StatusCode && httpResp.Header.Get(base.HttpHeaderAcceptRanges) == base.HttpHeaderBytes && strings.HasPrefix(httpResp.Header.Get(base.HttpHeaderContentRange), base.HttpHeaderBytes)) {
|
if base.HttpCodePartialContent == httpResp.StatusCode || (base.HttpCodeOK == httpResp.StatusCode && httpResp.Header.Get(base.HttpHeaderAcceptRanges) == base.HttpHeaderBytes && strings.HasPrefix(httpResp.Header.Get(base.HttpHeaderContentRange), base.HttpHeaderBytes)) {
|
||||||
// 1.返回206响应码表示支持断点下载 2.不返回206但是Accept-Ranges首部并且等于bytes也表示支持断点下载
|
// 1.返回206响应码表示支持断点下载 2.不返回206但是Accept-Ranges首部并且等于bytes也表示支持断点下载
|
||||||
res.Range = true
|
res.Range = true
|
||||||
@@ -130,8 +132,17 @@ func (f *Fetcher) Resolve(req *base.Request) error {
|
|||||||
} else {
|
} else {
|
||||||
return NewRequestError(httpResp.StatusCode, httpResp.Status)
|
return NewRequestError(httpResp.StatusCode, httpResp.Status)
|
||||||
}
|
}
|
||||||
|
// Parse last modified time
|
||||||
|
var lastModifiedTime *time.Time
|
||||||
|
lastModified := httpResp.Header.Get(base.HttpHeaderLastModified)
|
||||||
|
if lastModified != "" {
|
||||||
|
// ignore parse error
|
||||||
|
t, _ := time.Parse(time.RFC1123, lastModified)
|
||||||
|
lastModifiedTime = &t
|
||||||
|
}
|
||||||
file := &base.FileInfo{
|
file := &base.FileInfo{
|
||||||
Size: res.Size,
|
Size: res.Size,
|
||||||
|
Ctime: lastModifiedTime,
|
||||||
}
|
}
|
||||||
contentDisposition := httpResp.Header.Get(base.HttpHeaderContentDisposition)
|
contentDisposition := httpResp.Header.Get(base.HttpHeaderContentDisposition)
|
||||||
if contentDisposition != "" {
|
if contentDisposition != "" {
|
||||||
@@ -257,6 +268,10 @@ func (f *Fetcher) fetch() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
f.file.Close()
|
f.file.Close()
|
||||||
|
// Update file last modified time
|
||||||
|
if f.config.UseServerCtime && f.meta.Res.Files[0].Ctime != nil {
|
||||||
|
setft.SetFileTime(f.file.Name(), time.Now(), *f.meta.Res.Files[0].Ctime, *f.meta.Res.Files[0].Ctime)
|
||||||
|
}
|
||||||
f.doneCh <- err
|
f.doneCh <- err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
@@ -265,17 +280,13 @@ func (f *Fetcher) fetchChunk(index int, ctx context.Context) (err error) {
|
|||||||
chunk := f.chunks[index]
|
chunk := f.chunks[index]
|
||||||
chunk.retryTimes = 0
|
chunk.retryTimes = 0
|
||||||
|
|
||||||
httpReq, err := f.buildRequest(ctx, f.meta.Req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var (
|
var (
|
||||||
client = f.buildClient()
|
client = f.buildClient()
|
||||||
buf = make([]byte, 8192)
|
buf = make([]byte, 8192)
|
||||||
maxRetries = 3
|
maxRetries = 3
|
||||||
)
|
)
|
||||||
// retry until all remain chunks failed
|
// retry until all remain chunks failed
|
||||||
for true {
|
for {
|
||||||
// if chunk is completed, return
|
// if chunk is completed, return
|
||||||
if f.meta.Res.Range && chunk.Downloaded >= chunk.End-chunk.Begin+1 {
|
if f.meta.Res.Range && chunk.Downloaded >= chunk.End-chunk.Begin+1 {
|
||||||
return
|
return
|
||||||
@@ -299,8 +310,13 @@ func (f *Fetcher) fetchChunk(index int, ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
httpReq *http.Request
|
||||||
resp *http.Response
|
resp *http.Response
|
||||||
)
|
)
|
||||||
|
httpReq, err = f.buildRequest(ctx, f.meta.Req)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if f.meta.Res.Range {
|
if f.meta.Res.Range {
|
||||||
httpReq.Header.Set(base.HttpHeaderRange,
|
httpReq.Header.Set(base.HttpHeaderRange,
|
||||||
fmt.Sprintf(base.HttpHeaderRangeFormat, chunk.Begin+chunk.Downloaded, chunk.End))
|
fmt.Sprintf(base.HttpHeaderRangeFormat, chunk.Begin+chunk.Downloaded, chunk.End))
|
||||||
@@ -435,12 +451,11 @@ func (f *Fetcher) splitChunk() (chunks []*chunk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fetcher) buildClient() *http.Client {
|
func (f *Fetcher) buildClient() *http.Client {
|
||||||
transport := &http.Transport{}
|
transport := &http.Transport{
|
||||||
|
Proxy: f.ctl.ProxyConfig.ToHandler(),
|
||||||
|
}
|
||||||
// Cookie handle
|
// Cookie handle
|
||||||
jar, _ := cookiejar.New(nil)
|
jar, _ := cookiejar.New(nil)
|
||||||
if f.ctl.ProxyUrl != nil {
|
|
||||||
transport.Proxy = http.ProxyURL(f.ctl.ProxyUrl)
|
|
||||||
}
|
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
Jar: jar,
|
Jar: jar,
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/internal/test"
|
"github.com/GopeedLab/gopeed/internal/test"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -69,7 +67,7 @@ func testResolve(startTestServer func() net.Listener, path string, want *base.Re
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(want, fetcher.meta.Res) {
|
if !test.AssertResourceEqual(want, fetcher.meta.Res) {
|
||||||
t.Errorf("Resolve() got = %v, want %v", fetcher.meta.Res, want)
|
t.Errorf("Resolve() got = %v, want %v", fetcher.meta.Res, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,10 +149,34 @@ func TestFetcher_DownloadWithProxy(t *testing.T) {
|
|||||||
downloadWithProxy(httpListener, proxyListener, t)
|
downloadWithProxy(httpListener, proxyListener, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetcher_Config(t *testing.T) {
|
func TestFetcher_ConfigConnections(t *testing.T) {
|
||||||
listener := test.StartTestFileServer()
|
listener := test.StartTestFileServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
fetcher := doDownloadReady(buildConfigFetcher(), listener, 0, t)
|
fetcher := doDownloadReady(buildConfigFetcher(config{
|
||||||
|
Connections: 16,
|
||||||
|
}), listener, 0, t)
|
||||||
|
err := fetcher.Start()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = fetcher.Wait()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
want := test.FileMd5(test.BuildFile)
|
||||||
|
got := test.FileMd5(test.DownloadFile)
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("Download() got = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_ConfigUseServerCtime(t *testing.T) {
|
||||||
|
listener := test.StartTestFileServer()
|
||||||
|
defer listener.Close()
|
||||||
|
fetcher := doDownloadReady(buildConfigFetcher(config{
|
||||||
|
Connections: 16,
|
||||||
|
UseServerCtime: true,
|
||||||
|
}), listener, 0, t)
|
||||||
err := fetcher.Start()
|
err := fetcher.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -315,7 +337,11 @@ func downloadResume(listener net.Listener, connections int, t *testing.T) {
|
|||||||
func downloadWithProxy(httpListener net.Listener, proxyListener net.Listener, t *testing.T) {
|
func downloadWithProxy(httpListener net.Listener, proxyListener net.Listener, t *testing.T) {
|
||||||
fetcher := downloadReady(httpListener, 4, t)
|
fetcher := downloadReady(httpListener, 4, t)
|
||||||
ctl := controller.NewController()
|
ctl := controller.NewController()
|
||||||
ctl.ProxyUrl = util.BuildProxyUrl("socks5", proxyListener.Addr().String(), "", "")
|
ctl.ProxyConfig = &base.DownloaderProxyConfig{
|
||||||
|
Enable: true,
|
||||||
|
Scheme: "socks5",
|
||||||
|
Host: proxyListener.Addr().String(),
|
||||||
|
}
|
||||||
fetcher.Setup(ctl)
|
fetcher.Setup(ctl)
|
||||||
err := fetcher.Start()
|
err := fetcher.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -338,14 +364,11 @@ func buildFetcher() *Fetcher {
|
|||||||
return fetcher.(*Fetcher)
|
return fetcher.(*Fetcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConfigFetcher() fetcher.Fetcher {
|
func buildConfigFetcher(cfg config) fetcher.Fetcher {
|
||||||
fetcher := new(FetcherBuilder).Build()
|
fetcher := new(FetcherBuilder).Build()
|
||||||
newController := controller.NewController()
|
newController := controller.NewController()
|
||||||
mockCfg := config{
|
|
||||||
Connections: 16,
|
|
||||||
}
|
|
||||||
newController.GetConfig = func(v any) bool {
|
newController.GetConfig = func(v any) bool {
|
||||||
if err := json.Unmarshal([]byte(test.ToJson(mockCfg)), v); err != nil {
|
if err := json.Unmarshal([]byte(test.ToJson(cfg)), v); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/armon/go-socks5"
|
"github.com/armon/go-socks5"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -22,6 +24,11 @@ const (
|
|||||||
Dir = "./"
|
Dir = "./"
|
||||||
BuildFile = Dir + BuildName
|
BuildFile = Dir + BuildName
|
||||||
|
|
||||||
|
ExternalDownloadUrl = "https://raw.githubusercontent.com/GopeedLab/gopeed/v1.5.6/_docs/img/banner.png"
|
||||||
|
ExternalDownloadName = "banner.png"
|
||||||
|
ExternalDownloadSize = 26416
|
||||||
|
//ExternalDownloadMd5 = "c67c6e3cae79a95342485676571e8a5c"
|
||||||
|
|
||||||
DownloadName = "download.data"
|
DownloadName = "download.data"
|
||||||
DownloadRename = "download (1).data"
|
DownloadRename = "download (1).data"
|
||||||
DownloadFile = Dir + DownloadName
|
DownloadFile = Dir + DownloadName
|
||||||
@@ -337,3 +344,11 @@ func StartSocks5Server(usr, pwd string) net.Listener {
|
|||||||
go server.Serve(listener)
|
go server.Serve(listener)
|
||||||
return listener
|
return listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AssertResourceEqual(want, got *base.Resource) bool {
|
||||||
|
// Ignore ctime
|
||||||
|
if got != nil && len(got.Files) > 0 {
|
||||||
|
got.Files[0].Ctime = nil
|
||||||
|
}
|
||||||
|
return reflect.DeepEqual(want, got)
|
||||||
|
}
|
||||||
@@ -20,7 +20,8 @@ const (
|
|||||||
HttpHeaderContentLength = "Content-Length"
|
HttpHeaderContentLength = "Content-Length"
|
||||||
HttpHeaderContentRange = "Content-Range"
|
HttpHeaderContentRange = "Content-Range"
|
||||||
HttpHeaderContentDisposition = "Content-Disposition"
|
HttpHeaderContentDisposition = "Content-Disposition"
|
||||||
HttpHeaderUserAgent = "Usr-Agent"
|
HttpHeaderUserAgent = "User-Agent"
|
||||||
|
HttpHeaderLastModified = "Last-Modified"
|
||||||
|
|
||||||
HttpHeaderBytes = "bytes"
|
HttpHeaderBytes = "bytes"
|
||||||
HttpHeaderRangeFormat = "bytes=%d-%d"
|
HttpHeaderRangeFormat = "bytes=%d-%d"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package base
|
||||||
|
|
||||||
|
// Version is the build version, set at build time, using `go build -ldflags "-X github.com/GopeedLab/gopeed/pkg/base.Version=1.0.0"`.
|
||||||
|
var Version string
|
||||||
|
var InDocker string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if Version == "" {
|
||||||
|
Version = "dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,11 @@ package base
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
"github.com/GopeedLab/gopeed/pkg/util"
|
||||||
|
"github.com/mattn/go-ieproxy"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Request download request
|
// Request download request
|
||||||
@@ -62,6 +66,7 @@ type FileInfo struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
|
Ctime *time.Time `json:"ctime"`
|
||||||
|
|
||||||
Req *Request `json:"req"`
|
Req *Request `json:"req"`
|
||||||
}
|
}
|
||||||
@@ -126,3 +131,88 @@ func ParseOptsExtra[E any](opts *Options) error {
|
|||||||
opts.Extra = &t
|
opts.Extra = &t
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DownloaderStoreConfig is the config that can restore the downloader.
|
||||||
|
type DownloaderStoreConfig struct {
|
||||||
|
FirstLoad bool `json:"-"` // FirstLoad is the flag that the config is first time init and not from store
|
||||||
|
|
||||||
|
DownloadDir string `json:"downloadDir"` // DownloadDir is the default directory to save the downloaded files
|
||||||
|
MaxRunning int `json:"maxRunning"` // MaxRunning is the max running download count
|
||||||
|
ProtocolConfig map[string]any `json:"protocolConfig"` // ProtocolConfig is special config for each protocol
|
||||||
|
Extra map[string]any `json:"extra"`
|
||||||
|
Proxy *DownloaderProxyConfig `json:"proxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *DownloaderStoreConfig) Init() *DownloaderStoreConfig {
|
||||||
|
if cfg.MaxRunning == 0 {
|
||||||
|
cfg.MaxRunning = 5
|
||||||
|
}
|
||||||
|
if cfg.Proxy == nil {
|
||||||
|
cfg.Proxy = &DownloaderProxyConfig{}
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
type DownloaderProxyConfig struct {
|
||||||
|
Enable bool `json:"enable"`
|
||||||
|
// System is the flag that use system proxy
|
||||||
|
System bool `json:"system"`
|
||||||
|
Scheme string `json:"scheme"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Usr string `json:"usr"`
|
||||||
|
Pwd string `json:"pwd"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *DownloaderProxyConfig) ToHandler() func(r *http.Request) (*url.URL, error) {
|
||||||
|
if cfg == nil || cfg.Enable == false {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if cfg.System {
|
||||||
|
ieproxy.ReloadConf()
|
||||||
|
return ieproxy.GetProxyFunc()
|
||||||
|
}
|
||||||
|
if cfg.Scheme == "" || cfg.Host == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return http.ProxyURL(util.BuildProxyUrl(cfg.Scheme, cfg.Host, cfg.Usr, cfg.Pwd))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUrl returns the proxy url, just for git clone
|
||||||
|
func (cfg *DownloaderProxyConfig) ToUrl() *url.URL {
|
||||||
|
if cfg == nil || cfg.Enable == false {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if cfg.System {
|
||||||
|
ieproxy.ReloadConf()
|
||||||
|
static := ieproxy.GetConf().Static
|
||||||
|
if static.Active && len(static.Protocols) > 0 {
|
||||||
|
// If only one protocol, use it
|
||||||
|
if len(static.Protocols) == 1 {
|
||||||
|
for _, v := range static.Protocols {
|
||||||
|
return parseUrlSafe(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check https
|
||||||
|
if v, ok := static.Protocols["https"]; ok {
|
||||||
|
return parseUrlSafe(v)
|
||||||
|
}
|
||||||
|
// Check http
|
||||||
|
if v, ok := static.Protocols["http"]; ok {
|
||||||
|
return parseUrlSafe(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if cfg.Scheme == "" || cfg.Host == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return util.BuildProxyUrl(cfg.Scheme, cfg.Host, cfg.Usr, cfg.Pwd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseUrlSafe(rawUrl string) *url.URL {
|
||||||
|
u, err := url.Parse(rawUrl)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return u
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrTaskNotFound = errors.New("task not found")
|
ErrTaskNotFound = errors.New("task not found")
|
||||||
|
ErrUnSupportedProtocol = errors.New("unsupported protocol")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Listener func(event *Event)
|
type Listener func(event *Event)
|
||||||
@@ -109,7 +110,7 @@ func (d *Downloader) Setup() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// load config from storage
|
// load config from storage
|
||||||
var cfg DownloaderStoreConfig
|
var cfg base.DownloaderStoreConfig
|
||||||
exist, err := d.storage.Get(bucketConfig, "config", &cfg)
|
exist, err := d.storage.Get(bucketConfig, "config", &cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -117,12 +118,17 @@ func (d *Downloader) Setup() error {
|
|||||||
if exist {
|
if exist {
|
||||||
d.cfg.DownloaderStoreConfig = &cfg
|
d.cfg.DownloaderStoreConfig = &cfg
|
||||||
} else {
|
} else {
|
||||||
d.cfg.DownloaderStoreConfig = &DownloaderStoreConfig{
|
d.cfg.DownloaderStoreConfig = &base.DownloaderStoreConfig{
|
||||||
FirstLoad: true,
|
FirstLoad: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// init default config
|
// init default config
|
||||||
d.cfg.DownloaderStoreConfig.Init()
|
d.cfg.DownloaderStoreConfig.Init()
|
||||||
|
for _, fb := range d.fetcherBuilders {
|
||||||
|
f := fb.Build()
|
||||||
|
d.setupFetcher(f)
|
||||||
|
|
||||||
|
}
|
||||||
// load tasks from storage
|
// load tasks from storage
|
||||||
var tasks []*Task
|
var tasks []*Task
|
||||||
if err = d.storage.List(bucketTask, &tasks); err != nil {
|
if err = d.storage.List(bucketTask, &tasks); err != nil {
|
||||||
@@ -166,8 +172,8 @@ func (d *Downloader) Setup() error {
|
|||||||
if len(d.tasks) > 0 {
|
if len(d.tasks) > 0 {
|
||||||
for _, task := range d.tasks {
|
for _, task := range d.tasks {
|
||||||
func() {
|
func() {
|
||||||
task.lock.Lock()
|
task.statusLock.Lock()
|
||||||
defer task.lock.Unlock()
|
defer task.statusLock.Unlock()
|
||||||
if task.Status != base.DownloadStatusRunning {
|
if task.Status != base.DownloadStatusRunning {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -211,7 +217,7 @@ func (d *Downloader) parseFb(url string) (fetcher.FetcherBuilder, error) {
|
|||||||
if ok {
|
if ok {
|
||||||
return fetchBuilder, nil
|
return fetchBuilder, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("unsupported protocol")
|
return nil, ErrUnSupportedProtocol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) setupFetcher(fetcher fetcher.Fetcher) {
|
func (d *Downloader) setupFetcher(fetcher fetcher.Fetcher) {
|
||||||
@@ -219,7 +225,7 @@ func (d *Downloader) setupFetcher(fetcher fetcher.Fetcher) {
|
|||||||
ctl.GetConfig = func(v any) bool {
|
ctl.GetConfig = func(v any) bool {
|
||||||
return d.getProtocolConfig(fetcher.Name(), v)
|
return d.getProtocolConfig(fetcher.Name(), v)
|
||||||
}
|
}
|
||||||
ctl.ProxyUrl = d.cfg.ProxyUrl()
|
ctl.ProxyConfig = d.cfg.Proxy
|
||||||
fetcher.Setup(ctl)
|
fetcher.Setup(ctl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,9 +302,6 @@ func (d *Downloader) CreateDirect(req *base.Request, opts *base.Options) (taskId
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) Create(rrId string, opts *base.Options) (taskId string, err error) {
|
func (d *Downloader) Create(rrId string, opts *base.Options) (taskId string, err error) {
|
||||||
if opts == nil {
|
|
||||||
opts = &base.Options{}
|
|
||||||
}
|
|
||||||
d.fetcherMapLock.RLock()
|
d.fetcherMapLock.RLock()
|
||||||
fetcher, ok := d.fetcherCache[rrId]
|
fetcher, ok := d.fetcherCache[rrId]
|
||||||
d.fetcherMapLock.RUnlock()
|
d.fetcherMapLock.RUnlock()
|
||||||
@@ -326,8 +329,7 @@ func (d *Downloader) Pause(id string) (err error) {
|
|||||||
if task.Status == base.DownloadStatusPause {
|
if task.Status == base.DownloadStatusPause {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = d.doPause(task)
|
if err = d.doPause(task); err != nil {
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
d.notifyRunning()
|
d.notifyRunning()
|
||||||
@@ -360,19 +362,7 @@ func (d *Downloader) Continue(id string) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
func() {
|
return d.doStart(task)
|
||||||
task.lock.Lock()
|
|
||||||
defer task.lock.Unlock()
|
|
||||||
|
|
||||||
if task.Status == base.DownloadStatusRunning {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = d.doStart(task); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) PauseAll() (err error) {
|
func (d *Downloader) PauseAll() (err error) {
|
||||||
@@ -385,13 +375,7 @@ func (d *Downloader) PauseAll() (err error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
for _, task := range d.tasks {
|
for _, task := range d.tasks {
|
||||||
err = func() error {
|
if err = d.doPause(task); err != nil {
|
||||||
task.lock.Lock()
|
|
||||||
defer task.lock.Unlock()
|
|
||||||
|
|
||||||
return d.doPause(task)
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,13 +405,7 @@ func (d *Downloader) ContinueAll() (err error) {
|
|||||||
|
|
||||||
for _, task := range continuedTasks {
|
for _, task := range continuedTasks {
|
||||||
tt := task
|
tt := task
|
||||||
err = func() error {
|
if err = d.doStart(tt); err != nil {
|
||||||
tt.lock.Lock()
|
|
||||||
defer tt.lock.Unlock()
|
|
||||||
|
|
||||||
return d.doStart(tt)
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,6 +426,13 @@ func (d *Downloader) Delete(id string, force bool) (err error) {
|
|||||||
for i, t := range d.tasks {
|
for i, t := range d.tasks {
|
||||||
if t.ID == id {
|
if t.ID == id {
|
||||||
d.tasks = append(d.tasks[:i], d.tasks[i+1:]...)
|
d.tasks = append(d.tasks[:i], d.tasks[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, t := range d.waitTasks {
|
||||||
|
if t.ID == id {
|
||||||
|
d.waitTasks = append(d.waitTasks[:i], d.waitTasks[i+1:]...)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -460,19 +445,73 @@ func (d *Downloader) Delete(id string, force bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) DeleteByStatues(statues []base.Status, force bool) (err error) {
|
||||||
|
deleteTasks := d.GetTasksByStatues(statues)
|
||||||
|
if len(deleteTasks) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteIds := make([]string, 0)
|
||||||
|
for _, task := range deleteTasks {
|
||||||
|
deleteIds = append(deleteIds, task.ID)
|
||||||
|
}
|
||||||
|
func() {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
for _, id := range deleteIds {
|
||||||
|
for i, t := range d.tasks {
|
||||||
|
if t.ID == id {
|
||||||
|
d.tasks = append(d.tasks[:i], d.tasks[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, t := range d.waitTasks {
|
||||||
|
if t.ID == id {
|
||||||
|
d.waitTasks = append(d.waitTasks[:i], d.waitTasks[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, task := range deleteTasks {
|
||||||
|
err = d.doDelete(task, force)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.notifyRunning()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) Stats(id string) (sr any, err error) {
|
||||||
|
task := d.GetTask(id)
|
||||||
|
if task == nil {
|
||||||
|
return sr, ErrTaskNotFound
|
||||||
|
}
|
||||||
|
sr = task.fetcher.Stats()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Downloader) doDelete(task *Task, force bool) (err error) {
|
func (d *Downloader) doDelete(task *Task, force bool) (err error) {
|
||||||
err = func() error {
|
err = func() error {
|
||||||
if task.fetcher != nil {
|
d.lock.Lock()
|
||||||
if err := task.fetcher.Close(); err != nil {
|
defer d.lock.Unlock()
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := d.storage.Delete(bucketTask, task.ID); err != nil {
|
if err := d.storage.Delete(bucketTask, task.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := d.storage.Delete(bucketSave, task.ID); err != nil {
|
if err := d.storage.Delete(bucketSave, task.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if task.fetcher != nil {
|
||||||
|
if err := task.fetcher.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if force && task.Meta.Res != nil {
|
if force && task.Meta.Res != nil {
|
||||||
if task.Meta.Res.Name != "" {
|
if task.Meta.Res.Name != "" {
|
||||||
if err := os.RemoveAll(task.Meta.FolderPath()); err != nil {
|
if err := os.RemoveAll(task.Meta.FolderPath()); err != nil {
|
||||||
@@ -548,11 +587,27 @@ func (d *Downloader) GetTasks() []*Task {
|
|||||||
return d.tasks
|
return d.tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) GetConfig() (*DownloaderStoreConfig, error) {
|
func (d *Downloader) GetTasksByStatues(statues []base.Status) []*Task {
|
||||||
|
if len(statues) == 0 {
|
||||||
|
return d.tasks
|
||||||
|
}
|
||||||
|
tasks := make([]*Task, 0)
|
||||||
|
for _, task := range d.tasks {
|
||||||
|
for _, status := range statues {
|
||||||
|
if task.Status == status {
|
||||||
|
tasks = append(tasks, task)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tasks
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) GetConfig() (*base.DownloaderStoreConfig, error) {
|
||||||
return d.cfg.DownloaderStoreConfig, nil
|
return d.cfg.DownloaderStoreConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) PutConfig(v *DownloaderStoreConfig) error {
|
func (d *Downloader) PutConfig(v *base.DownloaderStoreConfig) error {
|
||||||
d.cfg.DownloaderStoreConfig = v
|
d.cfg.DownloaderStoreConfig = v
|
||||||
return d.storage.Put(bucketConfig, "config", v)
|
return d.storage.Put(bucketConfig, "config", v)
|
||||||
}
|
}
|
||||||
@@ -671,6 +726,9 @@ func (d *Downloader) doCreate(fetcher fetcher.Fetcher, opts *base.Options) (task
|
|||||||
if opts == nil {
|
if opts == nil {
|
||||||
opts = &base.Options{}
|
opts = &base.Options{}
|
||||||
}
|
}
|
||||||
|
if opts.SelectFiles == nil {
|
||||||
|
opts.SelectFiles = make([]int, 0)
|
||||||
|
}
|
||||||
|
|
||||||
meta := fetcher.Meta()
|
meta := fetcher.Meta()
|
||||||
meta.Opts = opts
|
meta.Opts = opts
|
||||||
@@ -690,6 +748,7 @@ func (d *Downloader) doCreate(fetcher fetcher.Fetcher, opts *base.Options) (task
|
|||||||
task := NewTask()
|
task := NewTask()
|
||||||
task.fetcherBuilder = fb
|
task.fetcherBuilder = fb
|
||||||
task.fetcher = fetcher
|
task.fetcher = fetcher
|
||||||
|
task.Protocol = fetcher.Name()
|
||||||
task.Meta = fetcher.Meta()
|
task.Meta = fetcher.Meta()
|
||||||
task.Progress = &Progress{}
|
task.Progress = &Progress{}
|
||||||
initTask(task)
|
initTask(task)
|
||||||
@@ -714,31 +773,52 @@ func (d *Downloader) doCreate(fetcher fetcher.Fetcher, opts *base.Options) (task
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
d.doStart(task)
|
err = d.doStart(task)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go d.watch(task)
|
go d.watch(task)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Downloader) statusMut(task *Task, fn func() (bool, error)) (bool, error) {
|
||||||
|
task.statusLock.Lock()
|
||||||
|
defer task.statusLock.Unlock()
|
||||||
|
|
||||||
|
return fn()
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Downloader) doStart(task *Task) (err error) {
|
func (d *Downloader) doStart(task *Task) (err error) {
|
||||||
if task.Status != base.DownloadStatusRunning && task.Status != base.DownloadStatusDone {
|
var isCreate bool
|
||||||
err := d.restoreFetcher(task)
|
isReturn, err := d.statusMut(task, func() (isReturn bool, err error) {
|
||||||
|
if task.Status == base.DownloadStatusRunning || task.Status == base.DownloadStatusDone {
|
||||||
|
isReturn = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = d.restoreFetcher(task)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.Logger.Error().Stack().Err(err).Msgf("restore fetcher failed, task id: %s", task.ID)
|
d.Logger.Error().Stack().Err(err).Msgf("restore fetcher failed, task id: %s", task.ID)
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
}
|
isCreate = task.Status == base.DownloadStatusReady
|
||||||
|
|
||||||
isCreate := task.Status == base.DownloadStatusReady
|
|
||||||
|
|
||||||
doStart := func() error {
|
|
||||||
task.lock.Lock()
|
|
||||||
defer task.lock.Unlock()
|
|
||||||
|
|
||||||
d.triggerOnStart(task)
|
d.triggerOnStart(task)
|
||||||
task.updateStatus(base.DownloadStatusRunning)
|
task.updateStatus(base.DownloadStatusRunning)
|
||||||
|
|
||||||
|
return
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
d.Logger.Error().Stack().Err(err).Msgf("start task failed, task id: %s", task.ID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if isReturn {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := func() error {
|
||||||
|
task.lock.Lock()
|
||||||
|
defer task.lock.Unlock()
|
||||||
|
|
||||||
if task.Meta.Res == nil {
|
if task.Meta.Res == nil {
|
||||||
err := task.fetcher.Resolve(task.Meta.Req)
|
err := task.fetcher.Resolve(task.Meta.Req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -785,8 +865,7 @@ func (d *Downloader) doStart(task *Task) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
err := doStart()
|
if err := handler(); err != nil {
|
||||||
if err != nil {
|
|
||||||
d.doOnError(task, err)
|
d.doOnError(task, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -795,10 +874,28 @@ func (d *Downloader) doStart(task *Task) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Downloader) doPause(task *Task) (err error) {
|
func (d *Downloader) doPause(task *Task) (err error) {
|
||||||
err = func() error {
|
isReturn, err := d.statusMut(task, func() (isReturn bool, err error) {
|
||||||
if task.Status != base.DownloadStatusDone {
|
if task.Status == base.DownloadStatusPause || task.Status == base.DownloadStatusDone {
|
||||||
|
isReturn = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
task.updateStatus(base.DownloadStatusPause)
|
task.updateStatus(base.DownloadStatusPause)
|
||||||
task.timer.Pause()
|
task.timer.Pause()
|
||||||
|
return
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
d.Logger.Error().Stack().Err(err).Msgf("pause task failed, task id: %s", task.ID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if isReturn {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := func() error {
|
||||||
|
task.lock.Lock()
|
||||||
|
defer task.lock.Unlock()
|
||||||
|
|
||||||
if task.fetcher != nil {
|
if task.fetcher != nil {
|
||||||
if err := task.fetcher.Pause(); err != nil {
|
if err := task.fetcher.Pause(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -808,14 +905,13 @@ func (d *Downloader) doPause(task *Task) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
d.emit(EventKeyPause, task)
|
d.emit(EventKeyPause, task)
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
d.Logger.Error().Stack().Err(err).Msgf("pause task failed, task id: %s", task.ID)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
go func() {
|
||||||
|
if err := handler(); err != nil {
|
||||||
|
d.Logger.Error().Stack().Err(err).Msgf("pause task handle failed, task id: %s", task.ID)
|
||||||
|
}
|
||||||
|
}()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -843,6 +939,8 @@ func (d *Downloader) buildFetcher(url string) (fetcher.Fetcher, error) {
|
|||||||
|
|
||||||
func initTask(task *Task) {
|
func initTask(task *Task) {
|
||||||
task.timer = util.NewTimer(task.Progress.Used)
|
task.timer = util.NewTimer(task.Progress.Used)
|
||||||
|
|
||||||
|
task.statusLock = &sync.Mutex{}
|
||||||
task.lock = &sync.Mutex{}
|
task.lock = &sync.Mutex{}
|
||||||
task.speedArr = make([]int64, 0)
|
task.speedArr = make([]int64, 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/internal/test"
|
"github.com/GopeedLab/gopeed/internal/test"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
||||||
"reflect"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -37,7 +37,7 @@ func TestDownloader_Resolve(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(want, rr.Res) {
|
if !test.AssertResourceEqual(want, rr.Res) {
|
||||||
t.Errorf("Resolve() got = %v, want %v", rr.Res, want)
|
t.Errorf("Resolve() got = %v, want %v", rr.Res, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,37 +86,58 @@ func TestDownloader_Create(t *testing.T) {
|
|||||||
|
|
||||||
func TestDownloader_CreateWithProxy(t *testing.T) {
|
func TestDownloader_CreateWithProxy(t *testing.T) {
|
||||||
// No proxy
|
// No proxy
|
||||||
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig {
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
return nil
|
return nil
|
||||||
})
|
}, nil)
|
||||||
// Disable proxy
|
// Disable proxy
|
||||||
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig {
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
proxyCfg.Enable = false
|
proxyCfg.Enable = false
|
||||||
return proxyCfg
|
return proxyCfg
|
||||||
|
}, nil)
|
||||||
|
// Enable system proxy but not set proxy environment variable
|
||||||
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
|
proxyCfg.System = true
|
||||||
|
return proxyCfg
|
||||||
|
}, nil)
|
||||||
|
// Enable proxy but error proxy environment variable
|
||||||
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
|
os.Setenv("HTTP_PROXY", "http://127.0.0.1:1234")
|
||||||
|
os.Setenv("HTTPS_PROXY", "http://127.0.0.1:1234")
|
||||||
|
proxyCfg.System = true
|
||||||
|
return proxyCfg
|
||||||
|
}, func(err error) {
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("doTestDownloaderCreateWithProxy() got = nil, want error")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
// Enable system proxy and set proxy environment variable
|
||||||
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
|
os.Setenv("HTTP_PROXY", proxyCfg.ToUrl().String())
|
||||||
|
os.Setenv("HTTPS_PROXY", proxyCfg.ToUrl().String())
|
||||||
|
proxyCfg.System = true
|
||||||
|
return proxyCfg
|
||||||
|
}, nil)
|
||||||
// Invalid proxy scheme
|
// Invalid proxy scheme
|
||||||
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig {
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
proxyCfg.Scheme = ""
|
proxyCfg.Scheme = ""
|
||||||
return proxyCfg
|
return proxyCfg
|
||||||
})
|
}, nil)
|
||||||
// Invalid proxy host
|
// Invalid proxy host
|
||||||
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig {
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
proxyCfg.Host = ""
|
proxyCfg.Host = ""
|
||||||
return proxyCfg
|
return proxyCfg
|
||||||
})
|
}, nil)
|
||||||
// Use proxy without auth
|
// Use proxy without auth
|
||||||
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig {
|
doTestDownloaderCreateWithProxy(t, false, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
return proxyCfg
|
return proxyCfg
|
||||||
})
|
}, nil)
|
||||||
// Use proxy with auth
|
// Use proxy with auth
|
||||||
doTestDownloaderCreateWithProxy(t, true, func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig {
|
doTestDownloaderCreateWithProxy(t, true, func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig {
|
||||||
return proxyCfg
|
return proxyCfg
|
||||||
})
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doTestDownloaderCreateWithProxy(t *testing.T, auth bool, buildProxyConfig func(proxyCfg *DownloaderProxyConfig) *DownloaderProxyConfig) {
|
func doTestDownloaderCreateWithProxy(t *testing.T, auth bool, buildProxyConfig func(proxyCfg *base.DownloaderProxyConfig) *base.DownloaderProxyConfig, errHandler func(err error)) {
|
||||||
httpListener := test.StartTestFileServer()
|
|
||||||
defer httpListener.Close()
|
|
||||||
usr, pwd := "", ""
|
usr, pwd := "", ""
|
||||||
if auth {
|
if auth {
|
||||||
usr, pwd = "admin", "123"
|
usr, pwd = "admin", "123"
|
||||||
@@ -129,7 +150,7 @@ func doTestDownloaderCreateWithProxy(t *testing.T, auth bool, buildProxyConfig f
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer downloader.Clear()
|
defer downloader.Clear()
|
||||||
downloader.cfg.DownloaderStoreConfig.Proxy = buildProxyConfig(&DownloaderProxyConfig{
|
downloader.cfg.DownloaderStoreConfig.Proxy = buildProxyConfig(&base.DownloaderProxyConfig{
|
||||||
Enable: true,
|
Enable: true,
|
||||||
Scheme: "socks5",
|
Scheme: "socks5",
|
||||||
Host: proxyListener.Addr().String(),
|
Host: proxyListener.Addr().String(),
|
||||||
@@ -138,24 +159,28 @@ func doTestDownloaderCreateWithProxy(t *testing.T, auth bool, buildProxyConfig f
|
|||||||
})
|
})
|
||||||
|
|
||||||
req := &base.Request{
|
req := &base.Request{
|
||||||
URL: "http://" + httpListener.Addr().String() + "/" + test.BuildName,
|
URL: test.ExternalDownloadUrl,
|
||||||
}
|
}
|
||||||
rr, err := downloader.Resolve(req)
|
rr, err := downloader.Resolve(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errHandler == nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
errHandler(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
want := &base.Resource{
|
want := &base.Resource{
|
||||||
Size: test.BuildSize,
|
Size: test.ExternalDownloadSize,
|
||||||
Range: true,
|
Range: true,
|
||||||
Files: []*base.FileInfo{
|
Files: []*base.FileInfo{
|
||||||
{
|
{
|
||||||
Name: test.BuildName,
|
Name: test.ExternalDownloadName,
|
||||||
Path: "",
|
Path: "",
|
||||||
Size: test.BuildSize,
|
Size: test.ExternalDownloadSize,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(want, rr.Res) {
|
if !test.AssertResourceEqual(want, rr.Res) {
|
||||||
t.Errorf("Resolve() got = %v, want %v", rr.Res, want)
|
t.Errorf("Resolve() got = %v, want %v", rr.Res, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,7 +311,7 @@ func TestDownloader_Protocol_Config(t *testing.T) {
|
|||||||
t.Errorf("getProtocolConfig() got = %v, want %v", exits, false)
|
t.Errorf("getProtocolConfig() got = %v, want %v", exits, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
storeCfg := &DownloaderStoreConfig{
|
storeCfg := &base.DownloaderStoreConfig{
|
||||||
DownloadDir: "./downloads",
|
DownloadDir: "./downloads",
|
||||||
ProtocolConfig: map[string]any{
|
ProtocolConfig: map[string]any{
|
||||||
"http": map[string]any{
|
"http": map[string]any{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package engine
|
|||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
gojaerror "github.com/GopeedLab/gopeed/pkg/download/engine/inject/error"
|
gojaerror "github.com/GopeedLab/gopeed/pkg/download/engine/inject/error"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/file"
|
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/file"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/formdata"
|
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/formdata"
|
||||||
@@ -11,7 +12,6 @@ import (
|
|||||||
"github.com/dop251/goja"
|
"github.com/dop251/goja"
|
||||||
"github.com/dop251/goja_nodejs/eventloop"
|
"github.com/dop251/goja_nodejs/eventloop"
|
||||||
gojaurl "github.com/dop251/goja_nodejs/url"
|
gojaurl "github.com/dop251/goja_nodejs/url"
|
||||||
"net/url"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ func (e *Engine) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ProxyURL *url.URL
|
ProxyConfig *base.DownloaderProxyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEngine(cfg *Config) *Engine {
|
func NewEngine(cfg *Config) *Engine {
|
||||||
@@ -135,7 +135,7 @@ func NewEngine(cfg *Config) *Engine {
|
|||||||
if err := formdata.Enable(runtime); err != nil {
|
if err := formdata.Enable(runtime); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := xhr.Enable(runtime, cfg.ProxyURL); err != nil {
|
if err := xhr.Enable(runtime, cfg.ProxyConfig.ToHandler()); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := runtime.RunString(polyfillScript); err != nil {
|
if _, err := runtime.RunString(polyfillScript); err != nil {
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/GopeedLab/gopeed/internal/test"
|
"github.com/GopeedLab/gopeed/internal/test"
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
gojaerror "github.com/GopeedLab/gopeed/pkg/download/engine/inject/error"
|
gojaerror "github.com/GopeedLab/gopeed/pkg/download/engine/inject/error"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/file"
|
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/file"
|
||||||
gojautil "github.com/GopeedLab/gopeed/pkg/download/engine/util"
|
gojautil "github.com/GopeedLab/gopeed/pkg/download/engine/util"
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
|
||||||
"github.com/dop251/goja"
|
"github.com/dop251/goja"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@@ -217,8 +217,16 @@ func doTestFetchWithProxy(t *testing.T, usr, pwd string) {
|
|||||||
|
|
||||||
proxyListener := test.StartSocks5Server(usr, pwd)
|
proxyListener := test.StartSocks5Server(usr, pwd)
|
||||||
defer proxyListener.Close()
|
defer proxyListener.Close()
|
||||||
|
engine := NewEngine(&Config{
|
||||||
engine := NewEngine(&Config{ProxyURL: util.BuildProxyUrl("socks5", proxyListener.Addr().String(), usr, pwd)})
|
ProxyConfig: &base.DownloaderProxyConfig{
|
||||||
|
Enable: true,
|
||||||
|
System: false,
|
||||||
|
Scheme: "socks5",
|
||||||
|
Host: proxyListener.Addr().String(),
|
||||||
|
Usr: usr,
|
||||||
|
Pwd: pwd,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
if _, err := engine.RunString(fmt.Sprintf("var host = 'http://%s';", httpListener.Addr().String())); err != nil {
|
if _, err := engine.RunString(fmt.Sprintf("var host = 'http://%s';", httpListener.Addr().String())); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package xhr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/file"
|
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/file"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/formdata"
|
"github.com/GopeedLab/gopeed/pkg/download/engine/inject/formdata"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download/engine/util"
|
"github.com/GopeedLab/gopeed/pkg/download/engine/util"
|
||||||
@@ -120,7 +121,7 @@ type XMLHttpRequest struct {
|
|||||||
requestHeaders map[string]string
|
requestHeaders map[string]string
|
||||||
responseHeaders map[string]string
|
responseHeaders map[string]string
|
||||||
aborted bool
|
aborted bool
|
||||||
proxyUrl *url.URL
|
proxyHandler func(r *http.Request) (*url.URL, error)
|
||||||
|
|
||||||
Upload *XMLHttpRequestUpload `json:"upload"`
|
Upload *XMLHttpRequestUpload `json:"upload"`
|
||||||
Timeout int `json:"timeout"`
|
Timeout int `json:"timeout"`
|
||||||
@@ -202,9 +203,8 @@ func (xhr *XMLHttpRequest) Send(data goja.Value) {
|
|||||||
for k, v := range xhr.requestHeaders {
|
for k, v := range xhr.requestHeaders {
|
||||||
req.Header.Set(k, v)
|
req.Header.Set(k, v)
|
||||||
}
|
}
|
||||||
transport := &http.Transport{}
|
transport := &http.Transport{
|
||||||
if xhr.proxyUrl != nil {
|
Proxy: xhr.proxyHandler,
|
||||||
transport.Proxy = http.ProxyURL(xhr.proxyUrl)
|
|
||||||
}
|
}
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
@@ -213,7 +213,8 @@ func (xhr *XMLHttpRequest) Send(data goja.Value) {
|
|||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle timeout error
|
// handle timeout error
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
var ne net.Error
|
||||||
|
if errors.As(err, &ne) && ne.Timeout() {
|
||||||
if xhr.Timeout > 0 {
|
if xhr.Timeout > 0 {
|
||||||
xhr.Upload.callOntimeout()
|
xhr.Upload.callOntimeout()
|
||||||
xhr.callOntimeout()
|
xhr.callOntimeout()
|
||||||
@@ -313,7 +314,7 @@ func (xhr *XMLHttpRequest) parseData(data goja.Value) any {
|
|||||||
return data.String()
|
return data.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Enable(runtime *goja.Runtime, proxyUrl *url.URL) error {
|
func Enable(runtime *goja.Runtime, proxyHandler func(r *http.Request) (*url.URL, error)) error {
|
||||||
progressEvent := runtime.ToValue(func(call goja.ConstructorCall) *goja.Object {
|
progressEvent := runtime.ToValue(func(call goja.ConstructorCall) *goja.Object {
|
||||||
if len(call.Arguments) < 1 {
|
if len(call.Arguments) < 1 {
|
||||||
util.ThrowTypeError(runtime, "Failed to construct 'ProgressEvent': 1 argument required, but only 0 present.")
|
util.ThrowTypeError(runtime, "Failed to construct 'ProgressEvent': 1 argument required, but only 0 present.")
|
||||||
@@ -327,7 +328,7 @@ func Enable(runtime *goja.Runtime, proxyUrl *url.URL) error {
|
|||||||
})
|
})
|
||||||
xhr := runtime.ToValue(func(call goja.ConstructorCall) *goja.Object {
|
xhr := runtime.ToValue(func(call goja.ConstructorCall) *goja.Object {
|
||||||
instance := &XMLHttpRequest{
|
instance := &XMLHttpRequest{
|
||||||
proxyUrl: proxyUrl,
|
proxyHandler: proxyHandler,
|
||||||
Upload: &XMLHttpRequestUpload{
|
Upload: &XMLHttpRequestUpload{
|
||||||
EventProp: &EventProp{
|
EventProp: &EventProp{
|
||||||
eventListeners: make(map[string]func(event *ProgressEvent)),
|
eventListeners: make(map[string]func(event *ProgressEvent)),
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ func (d *Downloader) fetchExtensionByGit(url string, handler func(tempExtPath st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
proxyOptions := transport.ProxyOptions{}
|
proxyOptions := transport.ProxyOptions{}
|
||||||
proxyUrl := d.cfg.ProxyUrl()
|
proxyUrl := d.cfg.DownloaderStoreConfig.Proxy.ToUrl()
|
||||||
if proxyUrl != nil {
|
if proxyUrl != nil {
|
||||||
proxyOptions.URL = proxyUrl.Scheme + "://" + proxyUrl.Host
|
proxyOptions.URL = proxyUrl.Scheme + "://" + proxyUrl.Host
|
||||||
proxyOptions.Username = proxyUrl.User.Username()
|
proxyOptions.Username = proxyUrl.User.Username()
|
||||||
@@ -341,7 +341,7 @@ func doTrigger[T any](d *Downloader, event ActivationEvent, req *base.Request, c
|
|||||||
req.Labels = make(map[string]string)
|
req.Labels = make(map[string]string)
|
||||||
}
|
}
|
||||||
engine := engine.NewEngine(&engine.Config{
|
engine := engine.NewEngine(&engine.Config{
|
||||||
ProxyURL: d.cfg.ProxyUrl(),
|
ProxyConfig: d.cfg.Proxy,
|
||||||
})
|
})
|
||||||
defer engine.Close()
|
defer engine.Close()
|
||||||
err = engine.Runtime.Set("gopeed", gopeed)
|
err = engine.Runtime.Set("gopeed", gopeed)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/util"
|
"github.com/GopeedLab/gopeed/pkg/util"
|
||||||
gonanoid "github.com/matoous/go-nanoid/v2"
|
gonanoid "github.com/matoous/go-nanoid/v2"
|
||||||
"net/url"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -22,6 +21,7 @@ type Task struct {
|
|||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Meta *fetcher.FetcherMeta `json:"meta"`
|
Meta *fetcher.FetcherMeta `json:"meta"`
|
||||||
Status base.Status `json:"status"`
|
Status base.Status `json:"status"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
Progress *Progress `json:"progress"`
|
Progress *Progress `json:"progress"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
@@ -29,6 +29,7 @@ type Task struct {
|
|||||||
fetcherBuilder fetcher.FetcherBuilder
|
fetcherBuilder fetcher.FetcherBuilder
|
||||||
fetcher fetcher.Fetcher
|
fetcher fetcher.Fetcher
|
||||||
timer *util.Timer
|
timer *util.Timer
|
||||||
|
statusLock *sync.Mutex
|
||||||
lock *sync.Mutex
|
lock *sync.Mutex
|
||||||
speedArr []int64
|
speedArr []int64
|
||||||
}
|
}
|
||||||
@@ -84,7 +85,7 @@ type DownloaderConfig struct {
|
|||||||
|
|
||||||
ProductionMode bool
|
ProductionMode bool
|
||||||
|
|
||||||
*DownloaderStoreConfig
|
*base.DownloaderStoreConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *DownloaderConfig) Init() *DownloaderConfig {
|
func (cfg *DownloaderConfig) Init() *DownloaderConfig {
|
||||||
@@ -105,42 +106,3 @@ func (cfg *DownloaderConfig) Init() *DownloaderConfig {
|
|||||||
}
|
}
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloaderStoreConfig is the config that can restore the downloader.
|
|
||||||
type DownloaderStoreConfig struct {
|
|
||||||
FirstLoad bool `json:"-"` // FirstLoad is the flag that the config is first time init and not from store
|
|
||||||
|
|
||||||
DownloadDir string `json:"downloadDir"` // DownloadDir is the default directory to save the downloaded files
|
|
||||||
MaxRunning int `json:"maxRunning"` // MaxRunning is the max running download count
|
|
||||||
ProtocolConfig map[string]any `json:"protocolConfig"` // ProtocolConfig is special config for each protocol
|
|
||||||
Extra map[string]any `json:"extra"`
|
|
||||||
Proxy *DownloaderProxyConfig `json:"proxy"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *DownloaderStoreConfig) Init() *DownloaderStoreConfig {
|
|
||||||
if cfg.MaxRunning == 0 {
|
|
||||||
cfg.MaxRunning = 5
|
|
||||||
}
|
|
||||||
if cfg.Proxy == nil {
|
|
||||||
cfg.Proxy = &DownloaderProxyConfig{}
|
|
||||||
}
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg *DownloaderStoreConfig) ProxyUrl() *url.URL {
|
|
||||||
if cfg.Proxy == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if cfg.Proxy.Enable == false || cfg.Proxy.Scheme == "" || cfg.Proxy.Host == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return util.BuildProxyUrl(cfg.Proxy.Scheme, cfg.Proxy.Host, cfg.Proxy.Usr, cfg.Proxy.Pwd)
|
|
||||||
}
|
|
||||||
|
|
||||||
type DownloaderProxyConfig struct {
|
|
||||||
Enable bool `json:"enable"`
|
|
||||||
Scheme string `json:"scheme"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
Usr string `json:"usr"`
|
|
||||||
Pwd string `json:"pwd"`
|
|
||||||
}
|
|
||||||
@@ -104,6 +104,17 @@ func DeleteTask(w http.ResponseWriter, r *http.Request) {
|
|||||||
WriteJson(w, model.NewNilResult())
|
WriteJson(w, model.NewNilResult())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteTasks(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.ParseForm()
|
||||||
|
status := r.Form["status"]
|
||||||
|
force := r.FormValue("force")
|
||||||
|
if err := Downloader.DeleteByStatues(convertStatues(status), force == "true"); err != nil {
|
||||||
|
WriteJson(w, model.NewErrorResult(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
WriteJson(w, model.NewNilResult())
|
||||||
|
}
|
||||||
|
|
||||||
func GetTask(w http.ResponseWriter, r *http.Request) {
|
func GetTask(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
taskId := vars["id"]
|
taskId := vars["id"]
|
||||||
@@ -122,20 +133,8 @@ func GetTask(w http.ResponseWriter, r *http.Request) {
|
|||||||
func GetTasks(w http.ResponseWriter, r *http.Request) {
|
func GetTasks(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
status := r.Form["status"]
|
status := r.Form["status"]
|
||||||
tasks := Downloader.GetTasks()
|
tasks := Downloader.GetTasksByStatues(convertStatues(status))
|
||||||
if len(status) == 0 {
|
|
||||||
WriteJson(w, model.NewOkResult(tasks))
|
WriteJson(w, model.NewOkResult(tasks))
|
||||||
return
|
|
||||||
}
|
|
||||||
result := make([]*download.Task, 0)
|
|
||||||
for _, task := range tasks {
|
|
||||||
for _, s := range status {
|
|
||||||
if task.Status == base.Status(s) {
|
|
||||||
result = append(result, task)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WriteJson(w, model.NewOkResult(result))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetConfig(w http.ResponseWriter, r *http.Request) {
|
func GetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -143,7 +142,7 @@ func GetConfig(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PutConfig(w http.ResponseWriter, r *http.Request) {
|
func PutConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
var cfg download.DownloaderStoreConfig
|
var cfg base.DownloaderStoreConfig
|
||||||
if ReadJson(r, w, &cfg) {
|
if ReadJson(r, w, &cfg) {
|
||||||
if err := Downloader.PutConfig(&cfg); err != nil {
|
if err := Downloader.PutConfig(&cfg); err != nil {
|
||||||
WriteJson(w, model.NewErrorResult(err.Error()))
|
WriteJson(w, model.NewErrorResult(err.Error()))
|
||||||
@@ -282,12 +281,35 @@ func DoProxy(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(buf)
|
w.Write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetStats(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
taskId := vars["id"]
|
||||||
|
if taskId == "" {
|
||||||
|
WriteJson(w, model.NewErrorResult("param invalid: id", model.CodeInvalidParam))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
statsResult, err := Downloader.Stats(taskId)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
WriteJson(w, model.NewOkResult(statsResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertStatues(statues []string) []base.Status {
|
||||||
|
result := make([]base.Status, 0)
|
||||||
|
for _, status := range statues {
|
||||||
|
result = append(result, base.Status(status))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func writeError(w http.ResponseWriter, msg string) {
|
func writeError(w http.ResponseWriter, msg string) {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
w.Write([]byte(msg))
|
w.Write([]byte(msg))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getServerConfig() *download.DownloaderStoreConfig {
|
func getServerConfig() *base.DownloaderStoreConfig {
|
||||||
cfg, _ := Downloader.GetConfig()
|
cfg, _ := Downloader.GetConfig()
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
@@ -95,8 +95,10 @@ func BuildServer(startCfg *model.StartConfig) (*http.Server, net.Listener, error
|
|||||||
r.Methods(http.MethodPut).Path("/api/v1/tasks/pause").HandlerFunc(PauseAllTask)
|
r.Methods(http.MethodPut).Path("/api/v1/tasks/pause").HandlerFunc(PauseAllTask)
|
||||||
r.Methods(http.MethodPut).Path("/api/v1/tasks/continue").HandlerFunc(ContinueAllTask)
|
r.Methods(http.MethodPut).Path("/api/v1/tasks/continue").HandlerFunc(ContinueAllTask)
|
||||||
r.Methods(http.MethodDelete).Path("/api/v1/tasks/{id}").HandlerFunc(DeleteTask)
|
r.Methods(http.MethodDelete).Path("/api/v1/tasks/{id}").HandlerFunc(DeleteTask)
|
||||||
|
r.Methods(http.MethodDelete).Path("/api/v1/tasks").HandlerFunc(DeleteTasks)
|
||||||
r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}").HandlerFunc(GetTask)
|
r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}").HandlerFunc(GetTask)
|
||||||
r.Methods(http.MethodGet).Path("/api/v1/tasks").HandlerFunc(GetTasks)
|
r.Methods(http.MethodGet).Path("/api/v1/tasks").HandlerFunc(GetTasks)
|
||||||
|
r.Methods(http.MethodGet).Path("/api/v1/tasks/{id}/stats").HandlerFunc(GetStats)
|
||||||
r.Methods(http.MethodGet).Path("/api/v1/config").HandlerFunc(GetConfig)
|
r.Methods(http.MethodGet).Path("/api/v1/config").HandlerFunc(GetConfig)
|
||||||
r.Methods(http.MethodPut).Path("/api/v1/config").HandlerFunc(PutConfig)
|
r.Methods(http.MethodPut).Path("/api/v1/config").HandlerFunc(PutConfig)
|
||||||
r.Methods(http.MethodPost).Path("/api/v1/extensions").HandlerFunc(InstallExtension)
|
r.Methods(http.MethodPost).Path("/api/v1/extensions").HandlerFunc(InstallExtension)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ var (
|
|||||||
func TestResolve(t *testing.T) {
|
func TestResolve(t *testing.T) {
|
||||||
doTest(func() {
|
doTest(func() {
|
||||||
resp := httpRequestCheckOk[*download.ResolveResult](http.MethodPost, "/api/v1/resolve", taskReq)
|
resp := httpRequestCheckOk[*download.ResolveResult](http.MethodPost, "/api/v1/resolve", taskReq)
|
||||||
if !test.JsonEqual(taskRes, resp.Res) {
|
if !test.AssertResourceEqual(taskRes, resp.Res) {
|
||||||
t.Errorf("Resolve() got = %v, want %v", test.ToJson(resp.Res), test.ToJson(taskRes))
|
t.Errorf("Resolve() got = %v, want %v", test.ToJson(resp.Res), test.ToJson(taskRes))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -242,6 +242,58 @@ func TestDeleteTaskForce(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteAllTasks(t *testing.T) {
|
||||||
|
doTest(func() {
|
||||||
|
taskCount := 3
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(taskCount)
|
||||||
|
Downloader.Listener(func(event *download.Event) {
|
||||||
|
if event.Key == download.EventKeyFinally {
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := 0; i < taskCount; i++ {
|
||||||
|
httpRequestCheckOk[string](http.MethodPost, "/api/v1/tasks", createReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
httpRequestCheckOk[any](http.MethodDelete, "/api/v1/tasks?force=true", nil)
|
||||||
|
tasks := httpRequestCheckOk[[]*download.Task](http.MethodGet, "/api/v1/tasks", nil)
|
||||||
|
if len(tasks) != 0 {
|
||||||
|
t.Errorf("DeleteTasks() got = %v, want %v", len(tasks), 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteTasksByStatues(t *testing.T) {
|
||||||
|
doTest(func() {
|
||||||
|
taskCount := 3
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(taskCount)
|
||||||
|
Downloader.Listener(func(event *download.Event) {
|
||||||
|
if event.Key == download.EventKeyFinally {
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := 0; i < taskCount; i++ {
|
||||||
|
httpRequestCheckOk[string](http.MethodPost, "/api/v1/tasks", createReq)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
httpRequestCheckOk[any](http.MethodDelete, fmt.Sprintf("/api/v1/tasks?status=%s&force=true", base.DownloadStatusDone), nil)
|
||||||
|
tasks := httpRequestCheckOk[[]*download.Task](http.MethodGet, "/api/v1/tasks", nil)
|
||||||
|
if len(tasks) != 0 {
|
||||||
|
t.Errorf("DeleteTasks() got = %v, want %v", len(tasks), 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetTasks(t *testing.T) {
|
func TestGetTasks(t *testing.T) {
|
||||||
doTest(func() {
|
doTest(func() {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
@@ -272,7 +324,7 @@ func TestGetTasks(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetAndPutConfig(t *testing.T) {
|
func TestGetAndPutConfig(t *testing.T) {
|
||||||
doTest(func() {
|
doTest(func() {
|
||||||
cfg := httpRequestCheckOk[*download.DownloaderStoreConfig](http.MethodGet, "/api/v1/config", nil)
|
cfg := httpRequestCheckOk[*base.DownloaderStoreConfig](http.MethodGet, "/api/v1/config", nil)
|
||||||
cfg.DownloadDir = "./download"
|
cfg.DownloadDir = "./download"
|
||||||
cfg.Extra = map[string]any{
|
cfg.Extra = map[string]any{
|
||||||
"serverConfig": &Config{
|
"serverConfig": &Config{
|
||||||
@@ -283,7 +335,7 @@ func TestGetAndPutConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
httpRequestCheckOk[any](http.MethodPut, "/api/v1/config", cfg)
|
httpRequestCheckOk[any](http.MethodPut, "/api/v1/config", cfg)
|
||||||
|
|
||||||
newCfg := httpRequestCheckOk[*download.DownloaderStoreConfig](http.MethodGet, "/api/v1/config", nil)
|
newCfg := httpRequestCheckOk[*base.DownloaderStoreConfig](http.MethodGet, "/api/v1/config", nil)
|
||||||
if !test.JsonEqual(cfg, newCfg) {
|
if !test.JsonEqual(cfg, newCfg) {
|
||||||
t.Errorf("GetAndPutConfig() got = %v, want %v", test.ToJson(newCfg), test.ToJson(cfg))
|
t.Errorf("GetAndPutConfig() got = %v, want %v", test.ToJson(newCfg), test.ToJson(cfg))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
var unitArr = []string{"B", "KB", "MB", "GB", "TB", "EB"}
|
var unitArr = []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
|
||||||
|
|
||||||
func ByteFmt(size int64) string {
|
func ByteFmt(size int64) string {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package util
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -51,3 +52,14 @@ func BuildProxyUrl(scheme, host, usr, pwd string) *url.URL {
|
|||||||
Host: host,
|
Host: host,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProxyUrlToHandler gets the proxy handler from the proxy url.
|
||||||
|
func ProxyUrlToHandler(proxyUrl *url.URL) func(*http.Request) (*url.URL, error) {
|
||||||
|
if proxyUrl == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if proxyUrl.Scheme == "system" {
|
||||||
|
return http.ProxyFromEnvironment
|
||||||
|
}
|
||||||
|
return http.ProxyURL(proxyUrl)
|
||||||
|
}
|
||||||
@@ -64,3 +64,7 @@ windows/flutter/generated_plugin_registrant.h
|
|||||||
windows/flutter/generated_plugins.cmake
|
windows/flutter/generated_plugins.cmake
|
||||||
|
|
||||||
/extensions
|
/extensions
|
||||||
|
|
||||||
|
# Hive database files
|
||||||
|
database.hive
|
||||||
|
database.lock
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
package="com.gopeed">
|
package="com.gopeed">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
@@ -71,6 +72,13 @@
|
|||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="*/*" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<!-- Add android:stopWithTask option only when necessary. -->
|
<!-- Add android:stopWithTask option only when necessary. -->
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 714 B After Width: | Height: | Size: 890 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 7.7 KiB |
@@ -4,13 +4,16 @@ part 'downloader_config.g.dart';
|
|||||||
|
|
||||||
@JsonSerializable(explicitToJson: true)
|
@JsonSerializable(explicitToJson: true)
|
||||||
class DownloaderConfig {
|
class DownloaderConfig {
|
||||||
String downloadDir = '';
|
String downloadDir;
|
||||||
int maxRunning = 0;
|
int maxRunning;
|
||||||
ProtocolConfig protocolConfig = ProtocolConfig();
|
ProtocolConfig protocolConfig = ProtocolConfig();
|
||||||
ExtraConfig extra = ExtraConfig();
|
ExtraConfig extra = ExtraConfig();
|
||||||
ProxyConfig proxy = ProxyConfig();
|
ProxyConfig proxy = ProxyConfig();
|
||||||
|
|
||||||
DownloaderConfig();
|
DownloaderConfig({
|
||||||
|
this.downloadDir = '',
|
||||||
|
this.maxRunning = 0,
|
||||||
|
});
|
||||||
|
|
||||||
factory DownloaderConfig.fromJson(Map<String, dynamic> json) =>
|
factory DownloaderConfig.fromJson(Map<String, dynamic> json) =>
|
||||||
_$DownloaderConfigFromJson(json);
|
_$DownloaderConfigFromJson(json);
|
||||||
@@ -31,11 +34,16 @@ class ProtocolConfig {
|
|||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class HttpConfig {
|
class HttpConfig {
|
||||||
String userAgent =
|
String userAgent;
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36';
|
int connections;
|
||||||
int connections = 0;
|
bool useServerCtime;
|
||||||
|
|
||||||
HttpConfig();
|
HttpConfig({
|
||||||
|
this.userAgent =
|
||||||
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
|
||||||
|
this.connections = 16,
|
||||||
|
this.useServerCtime = false,
|
||||||
|
});
|
||||||
|
|
||||||
factory HttpConfig.fromJson(Map<String, dynamic> json) =>
|
factory HttpConfig.fromJson(Map<String, dynamic> json) =>
|
||||||
_$HttpConfigFromJson(json);
|
_$HttpConfigFromJson(json);
|
||||||
@@ -69,13 +77,21 @@ class ExtraConfig {
|
|||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class ProxyConfig {
|
class ProxyConfig {
|
||||||
bool enable = false;
|
bool enable;
|
||||||
String scheme = '';
|
bool system;
|
||||||
String host = '';
|
String scheme;
|
||||||
String usr = '';
|
String host;
|
||||||
String pwd = '';
|
String usr;
|
||||||
|
String pwd;
|
||||||
|
|
||||||
ProxyConfig();
|
ProxyConfig({
|
||||||
|
this.enable = false,
|
||||||
|
this.system = false,
|
||||||
|
this.scheme = '',
|
||||||
|
this.host = '',
|
||||||
|
this.usr = '',
|
||||||
|
this.pwd = '',
|
||||||
|
});
|
||||||
|
|
||||||
factory ProxyConfig.fromJson(Map<String, dynamic> json) =>
|
factory ProxyConfig.fromJson(Map<String, dynamic> json) =>
|
||||||
_$ProxyConfigFromJson(json);
|
_$ProxyConfigFromJson(json);
|
||||||
@@ -87,6 +103,7 @@ class ProxyConfig {
|
|||||||
class ExtraConfigBt {
|
class ExtraConfigBt {
|
||||||
List<String> trackerSubscribeUrls = [];
|
List<String> trackerSubscribeUrls = [];
|
||||||
List<String> subscribeTrackers = [];
|
List<String> subscribeTrackers = [];
|
||||||
|
bool autoUpdateTrackers = true;
|
||||||
DateTime? lastTrackerUpdateTime;
|
DateTime? lastTrackerUpdateTime;
|
||||||
|
|
||||||
List<String> customTrackers = [];
|
List<String> customTrackers = [];
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ part of 'downloader_config.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
DownloaderConfig _$DownloaderConfigFromJson(Map<String, dynamic> json) =>
|
DownloaderConfig _$DownloaderConfigFromJson(Map<String, dynamic> json) =>
|
||||||
DownloaderConfig()
|
DownloaderConfig(
|
||||||
..downloadDir = json['downloadDir'] as String
|
downloadDir: json['downloadDir'] as String? ?? '',
|
||||||
..maxRunning = json['maxRunning'] as int
|
maxRunning: (json['maxRunning'] as num?)?.toInt() ?? 0,
|
||||||
|
)
|
||||||
..protocolConfig = ProtocolConfig.fromJson(
|
..protocolConfig = ProtocolConfig.fromJson(
|
||||||
json['protocolConfig'] as Map<String, dynamic>?)
|
json['protocolConfig'] as Map<String, dynamic>?)
|
||||||
..extra = ExtraConfig.fromJson(json['extra'] as Map<String, dynamic>?)
|
..extra = ExtraConfig.fromJson(json['extra'] as Map<String, dynamic>?)
|
||||||
@@ -35,18 +36,22 @@ Map<String, dynamic> _$ProtocolConfigToJson(ProtocolConfig instance) =>
|
|||||||
'bt': instance.bt.toJson(),
|
'bt': instance.bt.toJson(),
|
||||||
};
|
};
|
||||||
|
|
||||||
HttpConfig _$HttpConfigFromJson(Map<String, dynamic> json) => HttpConfig()
|
HttpConfig _$HttpConfigFromJson(Map<String, dynamic> json) => HttpConfig(
|
||||||
..userAgent = json['userAgent'] as String
|
userAgent: json['userAgent'] as String? ??
|
||||||
..connections = json['connections'] as int;
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36',
|
||||||
|
connections: (json['connections'] as num?)?.toInt() ?? 16,
|
||||||
|
useServerCtime: json['useServerCtime'] as bool? ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$HttpConfigToJson(HttpConfig instance) =>
|
Map<String, dynamic> _$HttpConfigToJson(HttpConfig instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'userAgent': instance.userAgent,
|
'userAgent': instance.userAgent,
|
||||||
'connections': instance.connections,
|
'connections': instance.connections,
|
||||||
|
'useServerCtime': instance.useServerCtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
BtConfig _$BtConfigFromJson(Map<String, dynamic> json) => BtConfig()
|
BtConfig _$BtConfigFromJson(Map<String, dynamic> json) => BtConfig()
|
||||||
..listenPort = json['listenPort'] as int
|
..listenPort = (json['listenPort'] as num).toInt()
|
||||||
..trackers =
|
..trackers =
|
||||||
(json['trackers'] as List<dynamic>).map((e) => e as String).toList();
|
(json['trackers'] as List<dynamic>).map((e) => e as String).toList();
|
||||||
|
|
||||||
@@ -67,16 +72,19 @@ Map<String, dynamic> _$ExtraConfigToJson(ExtraConfig instance) =>
|
|||||||
'bt': instance.bt.toJson(),
|
'bt': instance.bt.toJson(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ProxyConfig _$ProxyConfigFromJson(Map<String, dynamic> json) => ProxyConfig()
|
ProxyConfig _$ProxyConfigFromJson(Map<String, dynamic> json) => ProxyConfig(
|
||||||
..enable = json['enable'] as bool
|
enable: json['enable'] as bool? ?? false,
|
||||||
..scheme = json['scheme'] as String
|
system: json['system'] as bool? ?? false,
|
||||||
..host = json['host'] as String
|
scheme: json['scheme'] as String? ?? '',
|
||||||
..usr = json['usr'] as String
|
host: json['host'] as String? ?? '',
|
||||||
..pwd = json['pwd'] as String;
|
usr: json['usr'] as String? ?? '',
|
||||||
|
pwd: json['pwd'] as String? ?? '',
|
||||||
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$ProxyConfigToJson(ProxyConfig instance) =>
|
Map<String, dynamic> _$ProxyConfigToJson(ProxyConfig instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'enable': instance.enable,
|
'enable': instance.enable,
|
||||||
|
'system': instance.system,
|
||||||
'scheme': instance.scheme,
|
'scheme': instance.scheme,
|
||||||
'host': instance.host,
|
'host': instance.host,
|
||||||
'usr': instance.usr,
|
'usr': instance.usr,
|
||||||
@@ -91,6 +99,7 @@ ExtraConfigBt _$ExtraConfigBtFromJson(Map<String, dynamic> json) =>
|
|||||||
..subscribeTrackers = (json['subscribeTrackers'] as List<dynamic>)
|
..subscribeTrackers = (json['subscribeTrackers'] as List<dynamic>)
|
||||||
.map((e) => e as String)
|
.map((e) => e as String)
|
||||||
.toList()
|
.toList()
|
||||||
|
..autoUpdateTrackers = json['autoUpdateTrackers'] as bool
|
||||||
..lastTrackerUpdateTime = json['lastTrackerUpdateTime'] == null
|
..lastTrackerUpdateTime = json['lastTrackerUpdateTime'] == null
|
||||||
? null
|
? null
|
||||||
: DateTime.parse(json['lastTrackerUpdateTime'] as String)
|
: DateTime.parse(json['lastTrackerUpdateTime'] as String)
|
||||||
@@ -102,6 +111,7 @@ Map<String, dynamic> _$ExtraConfigBtToJson(ExtraConfigBt instance) {
|
|||||||
final val = <String, dynamic>{
|
final val = <String, dynamic>{
|
||||||
'trackerSubscribeUrls': instance.trackerSubscribeUrls,
|
'trackerSubscribeUrls': instance.trackerSubscribeUrls,
|
||||||
'subscribeTrackers': instance.subscribeTrackers,
|
'subscribeTrackers': instance.subscribeTrackers,
|
||||||
|
'autoUpdateTrackers': instance.autoUpdateTrackers,
|
||||||
};
|
};
|
||||||
|
|
||||||
void writeNotNull(String key, dynamic value) {
|
void writeNotNull(String key, dynamic value) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class Options {
|
|||||||
Options({
|
Options({
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.path,
|
required this.path,
|
||||||
required this.selectFiles,
|
this.selectFiles = const [],
|
||||||
this.extra,
|
this.extra,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ part of 'options.dart';
|
|||||||
Options _$OptionsFromJson(Map<String, dynamic> json) => Options(
|
Options _$OptionsFromJson(Map<String, dynamic> json) => Options(
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
path: json['path'] as String,
|
path: json['path'] as String,
|
||||||
selectFiles:
|
selectFiles: (json['selectFiles'] as List<dynamic>?)
|
||||||
(json['selectFiles'] as List<dynamic>).map((e) => e as int).toList(),
|
?.map((e) => (e as num).toInt())
|
||||||
|
.toList() ??
|
||||||
|
const [],
|
||||||
extra: json['extra'],
|
extra: json['extra'],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ Map<String, dynamic> _$OptionsToJson(Options instance) {
|
|||||||
|
|
||||||
OptsExtraHttp _$OptsExtraHttpFromJson(Map<String, dynamic> json) =>
|
OptsExtraHttp _$OptsExtraHttpFromJson(Map<String, dynamic> json) =>
|
||||||
OptsExtraHttp()
|
OptsExtraHttp()
|
||||||
..connections = json['connections'] as int
|
..connections = (json['connections'] as num).toInt()
|
||||||
..autoTorrent = json['autoTorrent'] as bool;
|
..autoTorrent = json['autoTorrent'] as bool;
|
||||||
|
|
||||||
Map<String, dynamic> _$OptsExtraHttpToJson(OptsExtraHttp instance) =>
|
Map<String, dynamic> _$OptsExtraHttpToJson(OptsExtraHttp instance) =>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ part of 'resource.dart';
|
|||||||
|
|
||||||
Resource _$ResourceFromJson(Map<String, dynamic> json) => Resource(
|
Resource _$ResourceFromJson(Map<String, dynamic> json) => Resource(
|
||||||
name: json['name'] as String? ?? "",
|
name: json['name'] as String? ?? "",
|
||||||
size: json['size'] as int? ?? 0,
|
size: (json['size'] as num?)?.toInt() ?? 0,
|
||||||
range: json['range'] as bool? ?? false,
|
range: json['range'] as bool? ?? false,
|
||||||
files: (json['files'] as List<dynamic>)
|
files: (json['files'] as List<dynamic>)
|
||||||
.map((e) => FileInfo.fromJson(e as Map<String, dynamic>))
|
.map((e) => FileInfo.fromJson(e as Map<String, dynamic>))
|
||||||
@@ -27,7 +27,7 @@ Map<String, dynamic> _$ResourceToJson(Resource instance) => <String, dynamic>{
|
|||||||
FileInfo _$FileInfoFromJson(Map<String, dynamic> json) => FileInfo(
|
FileInfo _$FileInfoFromJson(Map<String, dynamic> json) => FileInfo(
|
||||||
path: json['path'] as String? ?? "",
|
path: json['path'] as String? ?? "",
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
size: json['size'] as int? ?? 0,
|
size: (json['size'] as num?)?.toInt() ?? 0,
|
||||||
req: json['req'] == null
|
req: json['req'] == null
|
||||||
? null
|
? null
|
||||||
: Request.fromJson(json['req'] as Map<String, dynamic>),
|
: Request.fromJson(json['req'] as Map<String, dynamic>),
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Result<T> _$ResultFromJson<T>(
|
|||||||
T Function(Object? json) fromJsonT,
|
T Function(Object? json) fromJsonT,
|
||||||
) =>
|
) =>
|
||||||
Result<T>(
|
Result<T>(
|
||||||
code: json['code'] as int,
|
code: (json['code'] as num).toInt(),
|
||||||
msg: json['msg'] as String?,
|
msg: json['msg'] as String?,
|
||||||
data: _$nullableGenericFromJson(json['data'], fromJsonT),
|
data: _$nullableGenericFromJson(json['data'], fromJsonT),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ const _$StatusEnumMap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Progress _$ProgressFromJson(Map<String, dynamic> json) => Progress(
|
Progress _$ProgressFromJson(Map<String, dynamic> json) => Progress(
|
||||||
used: json['used'] as int,
|
used: (json['used'] as num).toInt(),
|
||||||
speed: json['speed'] as int,
|
speed: (json['speed'] as num).toInt(),
|
||||||
downloaded: json['downloaded'] as int,
|
downloaded: (json['downloaded'] as num).toInt(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$ProgressToJson(Progress instance) => <String, dynamic>{
|
Map<String, dynamic> _$ProgressToJson(Progress instance) => <String, dynamic>{
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import 'package:get/get.dart';
|
|
||||||
|
|
||||||
class ApiProvider extends GetConnect {
|
|
||||||
@override
|
|
||||||
void onInit() {
|
|
||||||
httpClient.baseUrl = 'YOUR-API-URL';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,9 +6,9 @@ import 'package:app_links/app_links.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:gopeed/database/entity.dart';
|
||||||
import 'package:lecle_downloads_path_provider/lecle_downloads_path_provider.dart';
|
import 'package:lecle_downloads_path_provider/lecle_downloads_path_provider.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:tray_manager/tray_manager.dart';
|
import 'package:tray_manager/tray_manager.dart';
|
||||||
import 'package:uri_to_file/uri_to_file.dart';
|
import 'package:uri_to_file/uri_to_file.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@@ -17,18 +17,14 @@ import 'package:window_manager/window_manager.dart';
|
|||||||
import '../../../../api/api.dart';
|
import '../../../../api/api.dart';
|
||||||
import '../../../../api/model/downloader_config.dart';
|
import '../../../../api/model/downloader_config.dart';
|
||||||
import '../../../../core/common/start_config.dart';
|
import '../../../../core/common/start_config.dart';
|
||||||
|
import '../../../../database/database.dart';
|
||||||
import '../../../../i18n/message.dart';
|
import '../../../../i18n/message.dart';
|
||||||
import '../../../../util/locale_manager.dart';
|
import '../../../../util/locale_manager.dart';
|
||||||
import '../../../../util/log_util.dart';
|
import '../../../../util/log_util.dart';
|
||||||
import '../../../../util/package_info.dart';
|
import '../../../../util/package_info.dart';
|
||||||
import '../../../../util/util.dart';
|
import '../../../../util/util.dart';
|
||||||
import '../../../../util/window_util.dart' as windows_util;
|
|
||||||
import '../../../routes/app_pages.dart';
|
import '../../../routes/app_pages.dart';
|
||||||
|
|
||||||
const _startConfigNetwork = "start.network";
|
|
||||||
const _startConfigAddress = "start.address";
|
|
||||||
const _startConfigApiToken = "start.apiToken";
|
|
||||||
|
|
||||||
const unixSocketPath = 'gopeed.sock';
|
const unixSocketPath = 'gopeed.sock';
|
||||||
|
|
||||||
const allTrackerSubscribeUrls = [
|
const allTrackerSubscribeUrls = [
|
||||||
@@ -99,6 +95,9 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
|
|
||||||
_initForegroundTask().onError((error, stackTrace) =>
|
_initForegroundTask().onError((error, stackTrace) =>
|
||||||
logger.w("initForegroundTask error", error, stackTrace));
|
logger.w("initForegroundTask error", error, stackTrace));
|
||||||
|
|
||||||
|
_initTrackerUpdate().onError((error, stackTrace) =>
|
||||||
|
logger.w("initTrackerUpdate error", error, stackTrace));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -127,17 +126,18 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void onWindowMaximize() {
|
void onWindowMaximize() {
|
||||||
windows_util.saveState(isMaximized: true);
|
Database.instance.saveWindowState(WindowStateEntity(isMaximized: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onWindowUnmaximize() {
|
void onWindowUnmaximize() {
|
||||||
windows_util.saveState(isMaximized: false);
|
Database.instance.saveWindowState(WindowStateEntity(isMaximized: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
final _windowsResizeSave = Util.debounce(() async {
|
final _windowsResizeSave = Util.debounce(() async {
|
||||||
final size = await windowManager.getSize();
|
final size = await windowManager.getSize();
|
||||||
windows_util.saveState(width: size.width, height: size.height);
|
Database.instance.saveWindowState(
|
||||||
|
WindowStateEntity(width: size.width, height: size.height));
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -274,7 +274,7 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _toCreate(Uri uri) async {
|
Future<void> _toCreate(Uri uri) async {
|
||||||
final path = uri.scheme == "magnet"
|
final path = (uri.scheme == "magnet" || uri.scheme == "http" || uri.scheme == "https")
|
||||||
? uri.toString()
|
? uri.toString()
|
||||||
: (await toFile(uri.toString())).path;
|
: (await toFile(uri.toString())).path;
|
||||||
await Get.rootDelegate.offAndToNamed(Routes.CREATE, arguments: path);
|
await Get.rootDelegate.offAndToNamed(Routes.CREATE, arguments: path);
|
||||||
@@ -307,13 +307,10 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
|
|
||||||
Future<void> loadStartConfig() async {
|
Future<void> loadStartConfig() async {
|
||||||
final defaultCfg = await _initDefaultStartConfig();
|
final defaultCfg = await _initDefaultStartConfig();
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final saveCfg = Database.instance.getStartConfig();
|
||||||
startConfig.value.network =
|
startConfig.value.network = saveCfg?.network ?? defaultCfg.network;
|
||||||
prefs.getString(_startConfigNetwork) ?? defaultCfg.network;
|
startConfig.value.address = saveCfg?.address ?? defaultCfg.address;
|
||||||
startConfig.value.address =
|
startConfig.value.apiToken = saveCfg?.apiToken ?? defaultCfg.apiToken;
|
||||||
prefs.getString(_startConfigAddress) ?? defaultCfg.address;
|
|
||||||
startConfig.value.apiToken =
|
|
||||||
prefs.getString(_startConfigApiToken) ?? defaultCfg.apiToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadDownloaderConfig() async {
|
Future<void> loadDownloaderConfig() async {
|
||||||
@@ -363,12 +360,13 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
btConfig.trackers.toSet().toList();
|
btConfig.trackers.toSet().toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> trackerUpdateOnStart() async {
|
Future<void> _initTrackerUpdate() async {
|
||||||
final btExtConfig = downloaderConfig.value.extra.bt;
|
final btExtConfig = downloaderConfig.value.extra.bt;
|
||||||
final lastUpdateTime = btExtConfig.lastTrackerUpdateTime;
|
final lastUpdateTime = btExtConfig.lastTrackerUpdateTime;
|
||||||
// if last update time is null or more than 1 day, update trackers
|
// if last update time is null or more than 1 day, update trackers
|
||||||
if (lastUpdateTime == null ||
|
if (btExtConfig.autoUpdateTrackers &&
|
||||||
lastUpdateTime.difference(DateTime.now()).inDays < 0) {
|
(lastUpdateTime == null ||
|
||||||
|
lastUpdateTime.difference(DateTime.now()).inDays < 0)) {
|
||||||
try {
|
try {
|
||||||
await trackerUpdate();
|
await trackerUpdate();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -392,9 +390,6 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
|
|
||||||
_initDownloaderConfig() async {
|
_initDownloaderConfig() async {
|
||||||
final config = downloaderConfig.value;
|
final config = downloaderConfig.value;
|
||||||
if (config.protocolConfig.http.connections == 0) {
|
|
||||||
config.protocolConfig.http.connections = 16;
|
|
||||||
}
|
|
||||||
final extra = config.extra;
|
final extra = config.extra;
|
||||||
if (extra.themeMode.isEmpty) {
|
if (extra.themeMode.isEmpty) {
|
||||||
extra.themeMode = ThemeMode.dark.name;
|
extra.themeMode = ThemeMode.dark.name;
|
||||||
@@ -417,13 +412,15 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
if (config.downloadDir.isEmpty) {
|
if (config.downloadDir.isEmpty) {
|
||||||
if (Util.isDesktop()) {
|
if (Util.isDesktop()) {
|
||||||
config.downloadDir = (await getDownloadsDirectory())?.path ?? "./";
|
config.downloadDir = (await getDownloadsDirectory())?.path ?? "./";
|
||||||
} else if (Util.isMobile()) {
|
} else if (Util.isAndroid()) {
|
||||||
final downloadDir = (await DownloadsPath.downloadsDirectory())?.path;
|
final downloadDir = (await DownloadsPath.downloadsDirectory())?.path;
|
||||||
if (downloadDir != null) {
|
if (downloadDir != null) {
|
||||||
config.downloadDir = '$downloadDir/Gopeed';
|
config.downloadDir = '$downloadDir/Gopeed';
|
||||||
} else {
|
} else {
|
||||||
config.downloadDir = (await getApplicationDocumentsDirectory()).path;
|
config.downloadDir = (await getApplicationDocumentsDirectory()).path;
|
||||||
}
|
}
|
||||||
|
} else if (Util.isIOS()) {
|
||||||
|
config.downloadDir = (await getApplicationDocumentsDirectory()).path;
|
||||||
} else {
|
} else {
|
||||||
config.downloadDir = './';
|
config.downloadDir = './';
|
||||||
}
|
}
|
||||||
@@ -431,10 +428,10 @@ class AppController extends GetxController with WindowListener, TrayListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveConfig() async {
|
Future<void> saveConfig() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
Database.instance.saveStartConfig(StartConfigEntity(
|
||||||
await prefs.setString(_startConfigNetwork, startConfig.value.network);
|
network: startConfig.value.network,
|
||||||
await prefs.setString(_startConfigAddress, startConfig.value.address);
|
address: startConfig.value.address,
|
||||||
await prefs.setString(_startConfigApiToken, startConfig.value.apiToken);
|
apiToken: startConfig.value.apiToken));
|
||||||
await putConfig(downloaderConfig.value);
|
await putConfig(downloaderConfig.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,13 +5,14 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:rounded_loading_button/rounded_loading_button.dart';
|
import 'package:rounded_loading_button_plus/rounded_loading_button.dart';
|
||||||
|
|
||||||
import '../../../../api/api.dart';
|
import '../../../../api/api.dart';
|
||||||
import '../../../../api/model/create_task.dart';
|
import '../../../../api/model/create_task.dart';
|
||||||
import '../../../../api/model/options.dart';
|
import '../../../../api/model/options.dart';
|
||||||
import '../../../../api/model/request.dart';
|
import '../../../../api/model/request.dart';
|
||||||
import '../../../../api/model/resolve_result.dart';
|
import '../../../../api/model/resolve_result.dart';
|
||||||
|
import '../../../../database/database.dart';
|
||||||
import '../../../../util/input_formatter.dart';
|
import '../../../../util/input_formatter.dart';
|
||||||
import '../../../../util/message.dart';
|
import '../../../../util/message.dart';
|
||||||
import '../../../../util/util.dart';
|
import '../../../../util/util.dart';
|
||||||
@@ -19,7 +20,6 @@ import '../../../routes/app_pages.dart';
|
|||||||
import '../../../views/directory_selector.dart';
|
import '../../../views/directory_selector.dart';
|
||||||
import '../../../views/file_list_view.dart';
|
import '../../../views/file_list_view.dart';
|
||||||
import '../../app/controllers/app_controller.dart';
|
import '../../app/controllers/app_controller.dart';
|
||||||
import '../../history/controller/history_controller.dart';
|
|
||||||
import '../../history/views/history_view.dart';
|
import '../../history/views/history_view.dart';
|
||||||
import '../controllers/create_controller.dart';
|
import '../controllers/create_controller.dart';
|
||||||
|
|
||||||
@@ -35,7 +35,6 @@ class CreateView extends GetView<CreateController> {
|
|||||||
final _httpCookieController = TextEditingController();
|
final _httpCookieController = TextEditingController();
|
||||||
final _httpRefererController = TextEditingController();
|
final _httpRefererController = TextEditingController();
|
||||||
final _btTrackerController = TextEditingController();
|
final _btTrackerController = TextEditingController();
|
||||||
final _historyController = HistoryController();
|
|
||||||
|
|
||||||
final _availableSchemes = ["http:", "https:", "magnet:"];
|
final _availableSchemes = ["http:", "https:", "magnet:"];
|
||||||
|
|
||||||
@@ -117,7 +116,7 @@ class CreateView extends GetView<CreateController> {
|
|||||||
Row(children: [
|
Row(children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
autofocus: true,
|
autofocus: !Util.isMobile(),
|
||||||
controller: _urlController,
|
controller: _urlController,
|
||||||
minLines: 1,
|
minLines: 1,
|
||||||
maxLines: 5,
|
maxLines: 5,
|
||||||
@@ -168,10 +167,7 @@ class CreateView extends GetView<CreateController> {
|
|||||||
icon: const Icon(Icons.history_rounded),
|
icon: const Icon(Icons.history_rounded),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
List<String> resultOfHistories =
|
List<String> resultOfHistories =
|
||||||
await _historyController.getAllHistory();
|
Database.instance.getCreateHistory() ?? [];
|
||||||
// reversing: display last entered history first
|
|
||||||
List<String> reverseResultOfHistories =
|
|
||||||
resultOfHistories.reversed.toList();
|
|
||||||
// show dialog box to list history
|
// show dialog box to list history
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showGeneralDialog(
|
showGeneralDialog(
|
||||||
@@ -183,16 +179,14 @@ class CreateView extends GetView<CreateController> {
|
|||||||
opacity: a1.value,
|
opacity: a1.value,
|
||||||
child: HistoryView(
|
child: HistoryView(
|
||||||
isHistoryListEmpty:
|
isHistoryListEmpty:
|
||||||
reverseResultOfHistories.isEmpty,
|
resultOfHistories.isEmpty,
|
||||||
historyList: ListView.builder(
|
historyList: ListView.builder(
|
||||||
itemCount:
|
itemCount: resultOfHistories.length,
|
||||||
reverseResultOfHistories.length,
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_urlController.text =
|
_urlController.text =
|
||||||
reverseResultOfHistories[
|
resultOfHistories[index];
|
||||||
index];
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
@@ -217,9 +211,7 @@ class CreateView extends GetView<CreateController> {
|
|||||||
10.0),
|
10.0),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
reverseResultOfHistories[
|
resultOfHistories[index],
|
||||||
index]
|
|
||||||
.toString(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -419,7 +411,7 @@ class CreateView extends GetView<CreateController> {
|
|||||||
// Add url to the history
|
// Add url to the history
|
||||||
if (!isWebFileChosen) {
|
if (!isWebFileChosen) {
|
||||||
for (final url in urls) {
|
for (final url in urls) {
|
||||||
_historyController.addHistory(url);
|
Database.instance.saveCreateHistory(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,21 +7,21 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:gopeed/app/views/text_button_loading.dart';
|
|
||||||
import '../../../../api/model/update_extension_settings.dart';
|
|
||||||
import '../../../../util/mac_secure_util.dart';
|
|
||||||
import '../../../../util/message.dart';
|
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
import 'package:rounded_loading_button/rounded_loading_button.dart';
|
import 'package:rounded_loading_button_plus/rounded_loading_button.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import '../../../../api/api.dart';
|
import '../../../../api/api.dart';
|
||||||
import '../../../../api/model/extension.dart';
|
import '../../../../api/model/extension.dart';
|
||||||
import '../../../../api/model/install_extension.dart';
|
import '../../../../api/model/install_extension.dart';
|
||||||
import '../../../../api/model/switch_extension.dart';
|
import '../../../../api/model/switch_extension.dart';
|
||||||
|
import '../../../../api/model/update_extension_settings.dart';
|
||||||
|
import '../../../../util/mac_secure_util.dart';
|
||||||
|
import '../../../../util/message.dart';
|
||||||
import '../../../../util/util.dart';
|
import '../../../../util/util.dart';
|
||||||
import '../../../views/icon_button_loading.dart';
|
import '../../../views/icon_button_loading.dart';
|
||||||
import '../../../views/responsive_builder.dart';
|
import '../../../views/responsive_builder.dart';
|
||||||
|
import '../../../views/text_button_loading.dart';
|
||||||
import '../controllers/extension_controller.dart';
|
import '../controllers/extension_controller.dart';
|
||||||
|
|
||||||
class ExtensionView extends GetView<ExtensionController> {
|
class ExtensionView extends GetView<ExtensionController> {
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
class HistoryController {
|
|
||||||
// Get History in List<String>
|
|
||||||
Future<List<String>> getAllHistory() async {
|
|
||||||
SharedPreferences preferences = await SharedPreferences.getInstance();
|
|
||||||
List<String>? historyList = preferences.getStringList('history');
|
|
||||||
if(historyList == null) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return historyList;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Existing History & Add New History
|
|
||||||
void addHistory(String historyText) async {
|
|
||||||
SharedPreferences preferences = await SharedPreferences.getInstance();
|
|
||||||
List<String> existingHistoryData = await getAllHistory();
|
|
||||||
existingHistoryData.add(historyText);
|
|
||||||
preferences.setStringList('history', existingHistoryData);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearHistory() async {
|
|
||||||
SharedPreferences preferences = await SharedPreferences.getInstance();
|
|
||||||
preferences.remove('history');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:gopeed/app/modules/history/controller/history_controller.dart';
|
import 'package:gopeed/database/database.dart';
|
||||||
|
|
||||||
class HistoryView extends StatefulWidget {
|
class HistoryView extends StatefulWidget {
|
||||||
const HistoryView({
|
const HistoryView({
|
||||||
@@ -62,8 +62,7 @@ class _HistoryViewState extends State<HistoryView> {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
HistoryController _controller = HistoryController();
|
Database.instance.clearCreateHistory();
|
||||||
_controller.clearHistory();
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
tooltip: "clearHistory".tr,
|
tooltip: "clearHistory".tr,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
import '../../../../api/model/downloader_config.dart';
|
||||||
import '../../../../i18n/message.dart';
|
import '../../../../i18n/message.dart';
|
||||||
import '../../../../util/input_formatter.dart';
|
import '../../../../util/input_formatter.dart';
|
||||||
import '../../../../util/locale_manager.dart';
|
import '../../../../util/locale_manager.dart';
|
||||||
@@ -15,6 +16,7 @@ import '../../../../util/package_info.dart';
|
|||||||
import '../../../../util/util.dart';
|
import '../../../../util/util.dart';
|
||||||
import '../../../views/check_list_view.dart';
|
import '../../../views/check_list_view.dart';
|
||||||
import '../../../views/directory_selector.dart';
|
import '../../../views/directory_selector.dart';
|
||||||
|
import '../../../views/open_in_new.dart';
|
||||||
import '../../../views/outlined_button_loading.dart';
|
import '../../../views/outlined_button_loading.dart';
|
||||||
import '../../app/controllers/app_controller.dart';
|
import '../../app/controllers/app_controller.dart';
|
||||||
import '../controllers/setting_controller.dart';
|
import '../controllers/setting_controller.dart';
|
||||||
@@ -93,6 +95,15 @@ class SettingView extends GetView<SettingController> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
buildBrowserExtension() {
|
||||||
|
return ListTile(
|
||||||
|
title: Text('browserExtension'.tr),
|
||||||
|
subtitle: const OpenInNew(
|
||||||
|
text: "Chrome",
|
||||||
|
url:
|
||||||
|
"https://chromewebstore.google.com/detail/gopeed/mijpgljlfcapndmchhjffkpckknofcnd",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// http config items start
|
// http config items start
|
||||||
final httpConfig = downloaderCfg.value.protocolConfig.http;
|
final httpConfig = downloaderCfg.value.protocolConfig.http;
|
||||||
@@ -138,6 +149,21 @@ class SettingView extends GetView<SettingController> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
final buildHttpUseServerCtime = _buildConfigItem('useServerCtime'.tr,
|
||||||
|
() => httpConfig.useServerCtime ? 'on'.tr : 'off'.tr, (Key key) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Switch(
|
||||||
|
value: httpConfig.useServerCtime,
|
||||||
|
onChanged: (bool value) {
|
||||||
|
downloaderCfg.update((val) {
|
||||||
|
val!.protocolConfig.http.useServerCtime = value;
|
||||||
|
});
|
||||||
|
debounceSave();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// bt config items start
|
// bt config items start
|
||||||
final btConfig = downloaderCfg.value.protocolConfig.bt;
|
final btConfig = downloaderCfg.value.protocolConfig.bt;
|
||||||
@@ -207,8 +233,13 @@ class SettingView extends GetView<SettingController> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: SwitchListTile(
|
child: SwitchListTile(
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
value: true,
|
value: btExtConfig.autoUpdateTrackers,
|
||||||
onChanged: (bool value) {},
|
onChanged: (bool value) {
|
||||||
|
downloaderCfg.update((val) {
|
||||||
|
val!.extra.bt.autoUpdateTrackers = value;
|
||||||
|
});
|
||||||
|
debounceSave();
|
||||||
|
},
|
||||||
title: Text('updateDaily'.tr)),
|
title: Text('updateDaily'.tr)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -378,29 +409,53 @@ class SettingView extends GetView<SettingController> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// advanced config proxy items start
|
// advanced config proxy items start
|
||||||
|
final proxy = downloaderCfg.value.proxy;
|
||||||
final buildProxy = _buildConfigItem(
|
final buildProxy = _buildConfigItem(
|
||||||
'proxy',
|
'proxy',
|
||||||
() => downloaderCfg.value.proxy.enable
|
() {
|
||||||
? '${downloaderCfg.value.proxy.scheme}://${downloaderCfg.value.proxy.host}'
|
switch (proxy.proxyMode) {
|
||||||
: 'notSet'.tr,
|
case ProxyModeEnum.noProxy:
|
||||||
|
return 'noProxy'.tr;
|
||||||
|
case ProxyModeEnum.systemProxy:
|
||||||
|
return 'systemProxy'.tr;
|
||||||
|
case ProxyModeEnum.customProxy:
|
||||||
|
return '${downloaderCfg.value.proxy.scheme}://${downloaderCfg.value.proxy.host}';
|
||||||
|
}
|
||||||
|
},
|
||||||
(Key key) {
|
(Key key) {
|
||||||
final proxy = downloaderCfg.value.proxy;
|
final mode = SizedBox(
|
||||||
|
width: 150,
|
||||||
final switcher = Switch(
|
child: DropdownButtonFormField<ProxyModeEnum>(
|
||||||
value: proxy.enable,
|
value: proxy.proxyMode,
|
||||||
onChanged: (bool value) async {
|
onChanged: (value) async {
|
||||||
if (value != proxy.enable) {
|
if (value != null && value != proxy.proxyMode) {
|
||||||
|
proxy.proxyMode = value;
|
||||||
downloaderCfg.update((val) {
|
downloaderCfg.update((val) {
|
||||||
val!.proxy.enable = value;
|
val!.proxy = proxy;
|
||||||
});
|
});
|
||||||
|
|
||||||
await debounceSave();
|
await debounceSave();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
items: [
|
||||||
|
DropdownMenuItem<ProxyModeEnum>(
|
||||||
|
value: ProxyModeEnum.noProxy,
|
||||||
|
child: Text('noProxy'.tr),
|
||||||
|
),
|
||||||
|
DropdownMenuItem<ProxyModeEnum>(
|
||||||
|
value: ProxyModeEnum.systemProxy,
|
||||||
|
child: Text('systemProxy'.tr),
|
||||||
|
),
|
||||||
|
DropdownMenuItem<ProxyModeEnum>(
|
||||||
|
value: ProxyModeEnum.customProxy,
|
||||||
|
child: Text('customProxy'.tr),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final scheme = SizedBox(
|
final scheme = SizedBox(
|
||||||
width: 100,
|
width: 150,
|
||||||
child: DropdownButtonFormField<String>(
|
child: DropdownButtonFormField<String>(
|
||||||
value: proxy.scheme,
|
value: proxy.scheme,
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
@@ -448,7 +503,7 @@ class SettingView extends GetView<SettingController> {
|
|||||||
|
|
||||||
ipController.addListener(updateAddress);
|
ipController.addListener(updateAddress);
|
||||||
portController.addListener(updateAddress);
|
portController.addListener(updateAddress);
|
||||||
final server = [
|
final server = Row(children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: ipController,
|
controller: ipController,
|
||||||
@@ -473,12 +528,12 @@ class SettingView extends GetView<SettingController> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
]);
|
||||||
|
|
||||||
final usrController = TextEditingController(text: proxy.usr);
|
final usrController = TextEditingController(text: proxy.usr);
|
||||||
final pwdController = TextEditingController(text: proxy.pwd);
|
final pwdController = TextEditingController(text: proxy.pwd);
|
||||||
|
|
||||||
final auth = [
|
final auth = Row(children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: usrController,
|
controller: usrController,
|
||||||
@@ -498,20 +553,21 @@ class SettingView extends GetView<SettingController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
]);
|
||||||
|
|
||||||
|
List<Widget> customView() {
|
||||||
|
if (proxy.proxyMode != ProxyModeEnum.customProxy) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [scheme, server, auth];
|
||||||
|
}
|
||||||
|
|
||||||
return Form(
|
return Form(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _addPadding([
|
children: _addPadding([
|
||||||
switcher,
|
mode,
|
||||||
scheme,
|
...customView(),
|
||||||
Row(
|
|
||||||
children: server,
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: auth,
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -667,8 +723,11 @@ class SettingView extends GetView<SettingController> {
|
|||||||
Text('general'.tr),
|
Text('general'.tr),
|
||||||
Card(
|
Card(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: _addDivider(
|
children: _addDivider([
|
||||||
[buildDownloadDir(), buildMaxRunning()]),
|
buildDownloadDir(),
|
||||||
|
buildMaxRunning(),
|
||||||
|
buildBrowserExtension()
|
||||||
|
]),
|
||||||
)),
|
)),
|
||||||
const Text('HTTP'),
|
const Text('HTTP'),
|
||||||
Card(
|
Card(
|
||||||
@@ -676,6 +735,7 @@ class SettingView extends GetView<SettingController> {
|
|||||||
children: _addDivider([
|
children: _addDivider([
|
||||||
buildHttpUa(),
|
buildHttpUa(),
|
||||||
buildHttpConnections(),
|
buildHttpConnections(),
|
||||||
|
buildHttpUseServerCtime(),
|
||||||
]),
|
]),
|
||||||
)),
|
)),
|
||||||
const Text('BitTorrent'),
|
const Text('BitTorrent'),
|
||||||
@@ -823,3 +883,37 @@ class SettingView extends GetView<SettingController> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ProxyModeEnum {
|
||||||
|
noProxy,
|
||||||
|
systemProxy,
|
||||||
|
customProxy,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ProxyMode on ProxyConfig {
|
||||||
|
ProxyModeEnum get proxyMode {
|
||||||
|
if (!enable) {
|
||||||
|
return ProxyModeEnum.noProxy;
|
||||||
|
}
|
||||||
|
if (system) {
|
||||||
|
return ProxyModeEnum.systemProxy;
|
||||||
|
}
|
||||||
|
return ProxyModeEnum.customProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
set proxyMode(ProxyModeEnum value) {
|
||||||
|
switch (value) {
|
||||||
|
case ProxyModeEnum.noProxy:
|
||||||
|
enable = false;
|
||||||
|
break;
|
||||||
|
case ProxyModeEnum.systemProxy:
|
||||||
|
enable = true;
|
||||||
|
system = true;
|
||||||
|
break;
|
||||||
|
case ProxyModeEnum.customProxy:
|
||||||
|
enable = true;
|
||||||
|
system = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class OpenInNew extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String url;
|
||||||
|
|
||||||
|
const OpenInNew({super.key, required this.text, required this.url});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Get.theme.colorScheme.background,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize
|
||||||
|
.min, // Set the row's size to be as small as possible
|
||||||
|
children: <Widget>[
|
||||||
|
Text(text),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4), // Add some space between the text and the icon
|
||||||
|
const Icon(
|
||||||
|
Icons.open_in_new,
|
||||||
|
size: 14,
|
||||||
|
), // The icon is after the text
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@ StartConfig _$StartConfigFromJson(Map<String, dynamic> json) => StartConfig()
|
|||||||
..address = json['address'] as String
|
..address = json['address'] as String
|
||||||
..storage = json['storage'] as String
|
..storage = json['storage'] as String
|
||||||
..storageDir = json['storageDir'] as String
|
..storageDir = json['storageDir'] as String
|
||||||
..refreshInterval = json['refreshInterval'] as int
|
..refreshInterval = (json['refreshInterval'] as num).toInt()
|
||||||
..apiToken = json['apiToken'] as String;
|
..apiToken = json['apiToken'] as String;
|
||||||
|
|
||||||
Map<String, dynamic> _$StartConfigToJson(StartConfig instance) =>
|
Map<String, dynamic> _$StartConfigToJson(StartConfig instance) =>
|
||||||
|
|||||||
@@ -0,0 +1,113 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:gopeed/util/util.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
import 'entity.dart';
|
||||||
|
|
||||||
|
const String _startConfig = 'startConfig';
|
||||||
|
const String _lastRunningConfig = 'lastRunningConfig';
|
||||||
|
const String _windowState = 'windowState';
|
||||||
|
const String _bookmark = 'bookmark';
|
||||||
|
const String _createHistory = 'createHistory';
|
||||||
|
|
||||||
|
class Database {
|
||||||
|
static final Database _instance = Database._internal();
|
||||||
|
|
||||||
|
static Database get instance => _instance;
|
||||||
|
|
||||||
|
factory Database() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
late Box box;
|
||||||
|
|
||||||
|
Database._internal();
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
Hive.init(Util.getStorageDir());
|
||||||
|
box = await Hive.openBox('database');
|
||||||
|
}
|
||||||
|
|
||||||
|
void save<T>(String key, T entity) {
|
||||||
|
box.put(key, jsonEncode(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
T? get<T>(String key, T Function(dynamic json) fromJsonT) {
|
||||||
|
final json = box.get(key);
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fromJsonT(jsonDecode(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(String key) {
|
||||||
|
box.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveStartConfig(StartConfigEntity entity) {
|
||||||
|
save<StartConfigEntity>(_startConfig, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
StartConfigEntity? getStartConfig() {
|
||||||
|
return get<StartConfigEntity>(
|
||||||
|
_startConfig, (json) => StartConfigEntity.fromJson(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveLastRunningConfig(StartConfigEntity entity) {
|
||||||
|
save<StartConfigEntity>(_lastRunningConfig, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
StartConfigEntity? getLastRunningConfig() {
|
||||||
|
return get<StartConfigEntity>(
|
||||||
|
_lastRunningConfig, (json) => StartConfigEntity.fromJson(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Patch non-null fields with the original value
|
||||||
|
void saveWindowState(WindowStateEntity entity) {
|
||||||
|
final state = getWindowState();
|
||||||
|
entity.isMaximized ??= state?.isMaximized;
|
||||||
|
entity.width ??= state?.width;
|
||||||
|
entity.height ??= state?.height;
|
||||||
|
save<WindowStateEntity>(_windowState, entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowStateEntity? getWindowState() {
|
||||||
|
return get<WindowStateEntity>(
|
||||||
|
_windowState, (json) => WindowStateEntity.fromJson(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Use map to ensure that the same directory only saves the latest bookmark
|
||||||
|
void saveBookmark(MapEntry<String, String> entry) {
|
||||||
|
final map = getBookmark() ?? {};
|
||||||
|
map[entry.key] = entry.value;
|
||||||
|
save<Map<String, String>>(_bookmark, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String>? getBookmark() {
|
||||||
|
return get<Map<String, String>>(_bookmark, (json) {
|
||||||
|
return (json as Map<String, dynamic>)
|
||||||
|
.map((key, value) => MapEntry(key, value.toString()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveCreateHistory(String url) {
|
||||||
|
var list = getCreateHistory() ?? [];
|
||||||
|
list.remove(url);
|
||||||
|
list.insert(0, url);
|
||||||
|
if (list.length > 64) {
|
||||||
|
list.removeLast();
|
||||||
|
}
|
||||||
|
save<List<String>>(_createHistory, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String>? getCreateHistory() {
|
||||||
|
return get<List<String>>(_createHistory, (json) {
|
||||||
|
return (json as List<dynamic>).map((e) => e.toString()).toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearCreateHistory() {
|
||||||
|
clear(_createHistory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'entity.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class StartConfigEntity {
|
||||||
|
String network;
|
||||||
|
String address;
|
||||||
|
String apiToken;
|
||||||
|
|
||||||
|
StartConfigEntity({
|
||||||
|
required this.network,
|
||||||
|
required this.address,
|
||||||
|
required this.apiToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory StartConfigEntity.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$StartConfigEntityFromJson(json);
|
||||||
|
Map<String, dynamic> toJson() => _$StartConfigEntityToJson(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class WindowStateEntity {
|
||||||
|
bool? isMaximized;
|
||||||
|
double? width;
|
||||||
|
double? height;
|
||||||
|
|
||||||
|
WindowStateEntity({
|
||||||
|
this.isMaximized,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory WindowStateEntity.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$WindowStateEntityFromJson(json);
|
||||||
|
Map<String, dynamic> toJson() => _$WindowStateEntityToJson(this);
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'entity.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
StartConfigEntity _$StartConfigEntityFromJson(Map<String, dynamic> json) =>
|
||||||
|
StartConfigEntity(
|
||||||
|
network: json['network'] as String,
|
||||||
|
address: json['address'] as String,
|
||||||
|
apiToken: json['apiToken'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$StartConfigEntityToJson(StartConfigEntity instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'network': instance.network,
|
||||||
|
'address': instance.address,
|
||||||
|
'apiToken': instance.apiToken,
|
||||||
|
};
|
||||||
|
|
||||||
|
WindowStateEntity _$WindowStateEntityFromJson(Map<String, dynamic> json) =>
|
||||||
|
WindowStateEntity(
|
||||||
|
isMaximized: json['isMaximized'] as bool?,
|
||||||
|
width: (json['width'] as num?)?.toDouble(),
|
||||||
|
height: (json['height'] as num?)?.toDouble(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$WindowStateEntityToJson(WindowStateEntity instance) {
|
||||||
|
final val = <String, dynamic>{};
|
||||||
|
|
||||||
|
void writeNotNull(String key, dynamic value) {
|
||||||
|
if (value != null) {
|
||||||
|
val[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeNotNull('isMaximized', instance.isMaximized);
|
||||||
|
writeNotNull('width', instance.width);
|
||||||
|
writeNotNull('height', instance.height);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@ const enUS = {
|
|||||||
'tip': 'Tip',
|
'tip': 'Tip',
|
||||||
'confirm': 'Confirm',
|
'confirm': 'Confirm',
|
||||||
'cancel': 'Cancel',
|
'cancel': 'Cancel',
|
||||||
|
'on': 'On',
|
||||||
|
'off': 'Off',
|
||||||
'selectAll': 'Select All',
|
'selectAll': 'Select All',
|
||||||
'task': 'Tasks',
|
'task': 'Tasks',
|
||||||
'downloading': 'downloading',
|
'downloading': 'downloading',
|
||||||
@@ -31,6 +33,7 @@ const enUS = {
|
|||||||
'downloadDir': 'Download Directory',
|
'downloadDir': 'Download Directory',
|
||||||
'downloadDirValid': 'Please select the download directory',
|
'downloadDirValid': 'Please select the download directory',
|
||||||
'connections': 'Connections',
|
'connections': 'Connections',
|
||||||
|
'useServerCtime': 'Use server time for file creation',
|
||||||
'maxRunning': 'Max Running Tasks',
|
'maxRunning': 'Max Running Tasks',
|
||||||
'items': '@count items',
|
'items': '@count items',
|
||||||
'subscribeTracker': 'Subscribe Tracker',
|
'subscribeTracker': 'Subscribe Tracker',
|
||||||
@@ -79,11 +82,15 @@ const enUS = {
|
|||||||
'serviceText': 'Running',
|
'serviceText': 'Running',
|
||||||
'network': 'Network',
|
'network': 'Network',
|
||||||
'proxy': 'Proxy',
|
'proxy': 'Proxy',
|
||||||
|
'noProxy': 'No Proxy',
|
||||||
|
'systemProxy': 'System Proxy',
|
||||||
|
'customProxy': 'Custom Proxy',
|
||||||
'server': 'Server',
|
'server': 'Server',
|
||||||
'username': 'Username',
|
'username': 'Username',
|
||||||
'password': 'Password',
|
'password': 'Password',
|
||||||
'thanks': 'Thanks',
|
'thanks': 'Thanks',
|
||||||
'thanksDesc':
|
'thanksDesc':
|
||||||
'Thanks to all the contributors who have helped build and develop the Gopeed community!',
|
'Thanks to all the contributors who have helped build and develop the Gopeed community!',
|
||||||
|
'browserExtension': 'Browser Extension',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -60,5 +60,6 @@ const faIR = {
|
|||||||
'thanks': 'تشکر',
|
'thanks': 'تشکر',
|
||||||
'thanksDesc':
|
'thanksDesc':
|
||||||
'از تمامی افرادی که در ساخت و توسعهی جامعهی Gopeed مشارکت کردهاند، سپاسگزاری میکنیم!',
|
'از تمامی افرادی که در ساخت و توسعهی جامعهی Gopeed مشارکت کردهاند، سپاسگزاری میکنیم!',
|
||||||
|
'browserExtension': 'فایل های دانلود شده را نگه دارد',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -61,5 +61,6 @@ const jaJP = {
|
|||||||
'newVersionLater': '後で',
|
'newVersionLater': '後で',
|
||||||
'thanks': '感謝',
|
'thanks': '感謝',
|
||||||
'thanksDesc': 'Gopeedコミュニティの建設に協力してくださったすべての貢献者の方々に感謝します!',
|
'thanksDesc': 'Gopeedコミュニティの建設に協力してくださったすべての貢献者の方々に感謝します!',
|
||||||
|
'browserExtension': 'ブラウザ拡張機能',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -76,5 +76,6 @@ const ruRU = {
|
|||||||
'thanks': 'Благодарности',
|
'thanks': 'Благодарности',
|
||||||
'thanksDesc':
|
'thanksDesc':
|
||||||
'Благодарим всех участников за их вклад в строительство и развитие сообщества Gopeed!',
|
'Благодарим всех участников за их вклад в строительство и развитие сообщества Gopeed!',
|
||||||
|
'browserExtension': 'Расширение браузера',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
const trTR = {
|
||||||
|
'tr_TR': {
|
||||||
|
'label': 'Türkçe',
|
||||||
|
'error': 'Hata',
|
||||||
|
'tip': 'İpucu',
|
||||||
|
'confirm': 'Onayla',
|
||||||
|
'cancel': 'İptal',
|
||||||
|
'on': 'Açık',
|
||||||
|
'off': 'Kapalı',
|
||||||
|
'selectAll': 'Hepsini seç',
|
||||||
|
'task': 'Görevler',
|
||||||
|
'downloading': 'indiriliyor',
|
||||||
|
'downloaded': 'indirildi',
|
||||||
|
'setting': 'Ayarlar',
|
||||||
|
'donate': 'Bağış',
|
||||||
|
'exit': 'Çık',
|
||||||
|
'create': 'Görev oluştur',
|
||||||
|
'directDownload': 'Doğrudan indir',
|
||||||
|
'advancedOptions': 'Gelişmiş ayarlar',
|
||||||
|
'downloadLink': 'İndirme bağlantısı',
|
||||||
|
'downloadLinkValid': 'Lütfen indirme bağlantısını girin',
|
||||||
|
'downloadLinkHit':
|
||||||
|
'Lütfen indirme bağlantısını girin, HTTP/HTTPS/MAGNET desteklenir@append',
|
||||||
|
'downloadLinkHitDesktop':
|
||||||
|
', veya torrent dosyasını doğrudan buraya sürükleyin',
|
||||||
|
'download': 'İndir',
|
||||||
|
'noFileSelected': 'Devam etmek için lütfen en az bir dosya seçin.',
|
||||||
|
'noStoragePermission': 'Depolama izni gerekli',
|
||||||
|
'selectFile': 'Dosya seç',
|
||||||
|
'rename': 'Yeniden adlandır',
|
||||||
|
'basic': 'Temel',
|
||||||
|
'advanced': 'Gelişmiş',
|
||||||
|
'general': 'Genel',
|
||||||
|
'downloadDir': 'İndirme dizini',
|
||||||
|
'downloadDirValid': 'Lütfen indirme dizinini seçin',
|
||||||
|
'connections': 'Bağlantılar',
|
||||||
|
'useServerCtime': 'Dosya oluşturma için sunucu saatini kullan',
|
||||||
|
'maxRunning': 'Maksimum çalışan görev sayısı',
|
||||||
|
'items': '@count tane',
|
||||||
|
'subscribeTracker': 'İzleyiciye abone ol',
|
||||||
|
'subscribeFail':
|
||||||
|
'Abone olunamadı, lütfen ağı kontrol edin veya daha sonra tekrar deneyin',
|
||||||
|
'update': 'Güncelle',
|
||||||
|
'updateDaily': 'Günlük olarak güncelle',
|
||||||
|
'lastUpdate': 'Son güncellenme tarihi: @time',
|
||||||
|
'addTracker': 'İzleyici ekle',
|
||||||
|
'addTrackerHit':
|
||||||
|
'Lütfen her satıra bir tane olmak üzere izleyici sunucusu bağlantısını girin',
|
||||||
|
'ui': 'Arayüz',
|
||||||
|
'theme': 'Tema',
|
||||||
|
'themeSystem': 'Sistem',
|
||||||
|
'themeLight': 'Açık',
|
||||||
|
'themeDark': 'Koyu',
|
||||||
|
'locale': 'Dil',
|
||||||
|
'about': 'Hakkında',
|
||||||
|
'homepage': 'Anasayfa',
|
||||||
|
'version': 'Sürüm',
|
||||||
|
'protocol': 'Protokol',
|
||||||
|
'port': 'Bağlantı noktası',
|
||||||
|
'apiToken': 'API anahtarı',
|
||||||
|
'notSet': 'AYARLI',
|
||||||
|
'set': 'AYARLI DEĞİL',
|
||||||
|
'effectAfterRestart': 'Yeniden başlatma sonrası etki edecektir',
|
||||||
|
'startAll': 'Hepsini başlat',
|
||||||
|
'pauseAll': 'Hepsini durdur',
|
||||||
|
'deleteTask': 'Görevleri sil',
|
||||||
|
'deleteTaskTip': 'İndirilen dosyaları sakla',
|
||||||
|
'delete': 'Sil',
|
||||||
|
'newVersionTitle': 'Yeni sürümü keşfet @version',
|
||||||
|
'newVersionUpdate': 'Şimdi güncelle',
|
||||||
|
'newVersionLater': 'Sonra',
|
||||||
|
'extensions': 'Uzantılar',
|
||||||
|
'extensionInstallUrl': 'İndirme bağlantısı',
|
||||||
|
'extensionInstallSuccess': 'Başarıyla indirildi',
|
||||||
|
'extensionUpdateSuccess': 'Başarıyla güncellendi',
|
||||||
|
'extensionDelete': 'Uzantıyı sil',
|
||||||
|
'extensionAlreadyLatest': 'Bu zaten en son sürüm',
|
||||||
|
'extensionFind': 'Uzantı ara',
|
||||||
|
'extensionDevelop': 'Uzantı geliştir',
|
||||||
|
'history': 'Geçmiş',
|
||||||
|
'clearHistory': 'Geçmişi temizle',
|
||||||
|
'noHistoryFound': 'Geçmiş bulunamadı',
|
||||||
|
'serviceTitle': 'Hizmet indir',
|
||||||
|
'serviceText': 'Çalışıyor',
|
||||||
|
'network': 'Ağ',
|
||||||
|
'proxy': 'Vekil',
|
||||||
|
'server': 'Sunucu',
|
||||||
|
'username': 'Kullanıcı adı',
|
||||||
|
'password': 'Şifre',
|
||||||
|
'thanks': 'Teşekkürler',
|
||||||
|
'thanksDesc':
|
||||||
|
'Gopeed topluluğunun oluşmasına ve gelişmesine yardımcı olan tüm katılımcılara teşekkürler!',
|
||||||
|
'browserExtension': 'Tarayıcı uzantısı',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
const viVN = {
|
||||||
|
'vi_VN': {
|
||||||
|
'label': 'Tiếng Việt',
|
||||||
|
'error': 'Lỗi',
|
||||||
|
'tip': 'Mẹo',
|
||||||
|
'confirm': 'Xác nhận',
|
||||||
|
'cancel': 'Hủy',
|
||||||
|
'on': 'Bật',
|
||||||
|
'off': 'Tắt',
|
||||||
|
'selectAll': 'Chọn tất cả',
|
||||||
|
'task': 'Nhiệm vụ',
|
||||||
|
'downloading': 'đang tải',
|
||||||
|
'downloaded': 'đã tải',
|
||||||
|
'setting': 'Cài đặt',
|
||||||
|
'donate': 'Ủng hộ',
|
||||||
|
'exit': 'Thoát',
|
||||||
|
'create': 'Tạo nhiệm vụ',
|
||||||
|
'directDownload': 'Tải trực tiếp',
|
||||||
|
'advancedOptions': 'Tùy chọn nâng cao',
|
||||||
|
'downloadLink': 'Liên kết tải về',
|
||||||
|
'downloadLinkValid': 'Vui lòng nhập liên kết tải về',
|
||||||
|
'downloadLinkHit':
|
||||||
|
'Vui lòng nhập liên kết tải về, hỗ trợ HTTP/HTTPS/MAGNET@append',
|
||||||
|
'downloadLinkHitDesktop': ', hoặc kéo tệp torrent vào đây trực tiếp',
|
||||||
|
'download': 'Tải về',
|
||||||
|
'noFileSelected': 'Vui lòng chọn ít nhất một tệp để tiếp tục.',
|
||||||
|
'noStoragePermission': 'Yêu cầu quyền lưu trữ',
|
||||||
|
'selectFile': 'Chọn tệp',
|
||||||
|
'rename': 'Đổi tên',
|
||||||
|
'basic': 'Cơ bản',
|
||||||
|
'advanced': 'Nâng cao',
|
||||||
|
'general': 'Chung',
|
||||||
|
'downloadDir': 'Thư mục tải về',
|
||||||
|
'downloadDirValid': 'Vui lòng chọn thư mục tải về',
|
||||||
|
'connections': 'Kết nối',
|
||||||
|
'useServerCtime': 'Sử dụng thời gian máy chủ cho việc tạo tệp',
|
||||||
|
'maxRunning': 'Số nhiệm vụ tối đa',
|
||||||
|
'items': '@count mục',
|
||||||
|
'subscribeTracker': 'Theo dõi Tracker',
|
||||||
|
'subscribeFail':
|
||||||
|
'Theo dõi thất bại, vui lòng kiểm tra kết nối mạng hoặc thử lại sau',
|
||||||
|
'update': 'Cập nhật',
|
||||||
|
'updateDaily': 'Cập nhật hàng ngày',
|
||||||
|
'lastUpdate': 'Cập nhật lần cuối: @time',
|
||||||
|
'addTracker': 'Thêm Tracker',
|
||||||
|
'addTrackerHit': 'Vui lòng nhập địa chỉ máy chủ tracker, mỗi dòng một',
|
||||||
|
'ui': 'Giao diện',
|
||||||
|
'theme': 'Chủ đề',
|
||||||
|
'themeSystem': 'Hệ thống',
|
||||||
|
'themeLight': 'Sáng',
|
||||||
|
'themeDark': 'Tối',
|
||||||
|
'locale': 'Ngôn ngữ',
|
||||||
|
'about': 'Về chúng tôi',
|
||||||
|
'homepage': 'Trang chủ',
|
||||||
|
'version': 'Phiên bản',
|
||||||
|
'protocol': 'Giao thức',
|
||||||
|
'port': 'Cổng',
|
||||||
|
'apiToken': 'Mã API',
|
||||||
|
'notSet': 'Chưa đặt',
|
||||||
|
'set': 'Đặt',
|
||||||
|
'effectAfterRestart': 'Hiệu lực sau khi khởi động lại',
|
||||||
|
'startAll': 'Bắt đầu tất cả',
|
||||||
|
'pauseAll': 'Tạm dừng tất cả',
|
||||||
|
'deleteTask': 'Xóa nhiệm vụ',
|
||||||
|
'deleteTaskTip': 'Giữ các tệp đã tải về',
|
||||||
|
'delete': 'Xóa',
|
||||||
|
'newVersionTitle': 'Khám phá phiên bản mới @version',
|
||||||
|
'newVersionUpdate': 'Cập nhật ngay',
|
||||||
|
'newVersionLater': 'Sau',
|
||||||
|
'extensions': 'Tiện ích mở rộng',
|
||||||
|
'extensionInstallUrl': 'Liên kết cài đặt',
|
||||||
|
'extensionInstallSuccess': 'Cài đặt thành công',
|
||||||
|
'extensionUpdateSuccess': 'Cập nhật thành công',
|
||||||
|
'extensionDelete': 'Xóa tiện ích mở rộng',
|
||||||
|
'extensionAlreadyLatest': 'Đây đã là phiên bản mới nhất',
|
||||||
|
'extensionFind': 'Tìm tiện ích mở rộng',
|
||||||
|
'extensionDevelop': 'Phát triển tiện ích mở rộng',
|
||||||
|
'history': 'Lịch sử',
|
||||||
|
'clearHistory': 'Xóa lịch sử',
|
||||||
|
'noHistoryFound': 'Không tìm thấy lịch sử',
|
||||||
|
'serviceTitle': 'Dịch vụ Tải xuống',
|
||||||
|
'serviceText': 'Đang chạy',
|
||||||
|
'network': 'Mạng',
|
||||||
|
'proxy': 'Proxy',
|
||||||
|
'server': 'Máy chủ',
|
||||||
|
'username': 'Tên đăng nhập',
|
||||||
|
'password': 'Mật khẩu',
|
||||||
|
'thanks': 'Cảm ơn',
|
||||||
|
'thanksDesc':
|
||||||
|
'Cảm ơn tất cả những người đóng góp đã giúp xây dựng và phát triển cộng đồng Gopeed!',
|
||||||
|
'browserExtension': 'Tiện ích mở rộng trình duyệt',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -5,6 +5,8 @@ const zhCN = {
|
|||||||
'tip': '提示',
|
'tip': '提示',
|
||||||
'confirm': '确认',
|
'confirm': '确认',
|
||||||
'cancel': '取消',
|
'cancel': '取消',
|
||||||
|
'on': '开启',
|
||||||
|
'off': '关闭',
|
||||||
'selectAll': '全选',
|
'selectAll': '全选',
|
||||||
'task': '任务',
|
'task': '任务',
|
||||||
'downloading': '下载中',
|
'downloading': '下载中',
|
||||||
@@ -30,6 +32,7 @@ const zhCN = {
|
|||||||
'downloadDir': '下载目录',
|
'downloadDir': '下载目录',
|
||||||
'downloadDirValid': '请选择下载目录',
|
'downloadDirValid': '请选择下载目录',
|
||||||
'connections': '连接数',
|
'connections': '连接数',
|
||||||
|
'useServerCtime': '创建文件使用服务器时间',
|
||||||
'maxRunning': '最大下载数',
|
'maxRunning': '最大下载数',
|
||||||
'items': '@count 项',
|
'items': '@count 项',
|
||||||
'subscribeTracker': '订阅 Tracker',
|
'subscribeTracker': '订阅 Tracker',
|
||||||
@@ -77,10 +80,14 @@ const zhCN = {
|
|||||||
'serviceText': '运行中',
|
'serviceText': '运行中',
|
||||||
'network': '网络',
|
'network': '网络',
|
||||||
'proxy': '代理',
|
'proxy': '代理',
|
||||||
|
'noProxy': '不使用代理',
|
||||||
|
'systemProxy': '系统代理',
|
||||||
|
'customProxy': '自定义代理',
|
||||||
'server': '服务器',
|
'server': '服务器',
|
||||||
'username': '用户名',
|
'username': '用户名',
|
||||||
'password': '密码',
|
'password': '密码',
|
||||||
'thanks': '鸣谢',
|
'thanks': '鸣谢',
|
||||||
'thanksDesc': '感谢所有为 Gopeed 社区建设添砖加瓦的贡献者们!',
|
'thanksDesc': '感谢所有为 Gopeed 社区建设添砖加瓦的贡献者们!',
|
||||||
|
'browserExtension': '浏览器扩展',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1,46 +1,49 @@
|
|||||||
const zhTW = {
|
const zhTW = {
|
||||||
"zh_TW": {
|
"zh_TW": {
|
||||||
'label': '中文 (繁體) ',
|
'label': '中文 (正體) ',
|
||||||
'error': '錯誤',
|
'error': '錯誤',
|
||||||
'tip': '提示',
|
'tip': '提示',
|
||||||
'confirm': '確定',
|
'confirm': '確定',
|
||||||
'cancel': '取消',
|
'cancel': '取消',
|
||||||
|
'on': '開啟',
|
||||||
|
'off': '關閉',
|
||||||
'selectAll': '全選',
|
'selectAll': '全選',
|
||||||
'task': '任務',
|
'task': '任務',
|
||||||
'downloading': '下載中',
|
'downloading': '下載中',
|
||||||
'downloaded': '已完成',
|
'downloaded': '已完成',
|
||||||
'setting': '設定',
|
'setting': '設定',
|
||||||
'donate': '斗內',
|
'donate': '鬥內',
|
||||||
'exit': '離開',
|
'exit': '離開',
|
||||||
'create': '新增任務',
|
'create': '新增任務',
|
||||||
'directDownload': '直接下載',
|
'directDownload': '直接下載',
|
||||||
'advancedOptions': '進階選項',
|
'advancedOptions': '進階選項',
|
||||||
'downloadLink': '下載鏈接',
|
'downloadLink': '下載連結',
|
||||||
'downloadLinkValid': '請輸入下載鏈接',
|
'downloadLinkValid': '請輸入下載連結',
|
||||||
'downloadLinkHit': '請輸入下載鏈接,支援 HTTP/HTTPS/MAGNET@append',
|
'downloadLinkHit': '請輸入下載連結,支援 HTTP/HTTPS/MAGNET@append',
|
||||||
'downloadLinkHitDesktop': ',也可以通過拖拽Torrent文件至此以新增任務',
|
'downloadLinkHitDesktop': ',也可以通過拖拽Torrent檔至此以新增任務',
|
||||||
'download': '下載',
|
'download': '下載',
|
||||||
'noFileSelected': '沒有選取的文件',
|
'noFileSelected': '沒有選取的檔案',
|
||||||
'noStoragePermission': '沒有存儲權限',
|
'noStoragePermission': '沒有存儲權',
|
||||||
'selectFile': '選擇文件',
|
'selectFile': '選擇檔案',
|
||||||
'rename': '重命名',
|
'rename': '重命名',
|
||||||
'basic': '一般',
|
'basic': '一般',
|
||||||
'advanced': '進階',
|
'advanced': '進階',
|
||||||
'general': '通用設定',
|
'general': '通用設定',
|
||||||
'downloadDir': '下載目録',
|
'downloadDir': '下載目錄',
|
||||||
'downloadDirValid': '請選擇下載目録',
|
'downloadDirValid': '請選擇下載目錄',
|
||||||
'connections': '同時連接數',
|
'connections': '同時連接數',
|
||||||
|
'useServerCtime': '使用伺服器時間作為檔案建立時間',
|
||||||
'maxRunning': '最大同時下載數',
|
'maxRunning': '最大同時下載數',
|
||||||
'items': '@count 項',
|
'items': '@count 項',
|
||||||
'subscribeTracker': '已訂閲的追蹤者列表',
|
'subscribeTracker': '已訂閱的追蹤者列表',
|
||||||
'subscribeFail': '訂閲失敗',
|
'subscribeFail': '訂閱失敗',
|
||||||
'update': '更新',
|
'update': '更新',
|
||||||
'updateDaily': '每天自動更新',
|
'updateDaily': '每天自動更新',
|
||||||
'lastUpdate': '上次更新時間: @time',
|
'lastUpdate': '上次更新時間: @time',
|
||||||
'addTracker': '增加新的追蹤者',
|
'addTracker': '增加新的追蹤者',
|
||||||
'addTrackerHit': '請輸入追蹤者服務器地址,每行一條',
|
'addTrackerHit': '請輸入追蹤者伺服器地址,每行一條',
|
||||||
'ui': '介面',
|
'ui': '介面',
|
||||||
'theme': '佈景主題',
|
'theme': '主題',
|
||||||
'themeSystem': '跟隨系統',
|
'themeSystem': '跟隨系統',
|
||||||
'themeLight': '亮色主題',
|
'themeLight': '亮色主題',
|
||||||
'themeDark': '深色主題',
|
'themeDark': '深色主題',
|
||||||
@@ -48,28 +51,28 @@ const zhTW = {
|
|||||||
'about': '關於',
|
'about': '關於',
|
||||||
'homepage': '訪問主頁',
|
'homepage': '訪問主頁',
|
||||||
'version': '版本資訊',
|
'version': '版本資訊',
|
||||||
'protocol': '端口設定',
|
'protocol': '通信協定',
|
||||||
'port': '端口',
|
'port': '埠',
|
||||||
'apiToken': '接口秘鑰',
|
'apiToken': 'API令牌',
|
||||||
'notSet': '未設定',
|
'notSet': '未設定',
|
||||||
'set': '已設定',
|
'set': '已設定',
|
||||||
'effectAfterRestart': '重啟後生效',
|
'effectAfterRestart': '重啟後生效',
|
||||||
'startAll': '全部開始',
|
'startAll': '全部開始',
|
||||||
'pauseAll': '全部暫停',
|
'pauseAll': '全部暫停',
|
||||||
'deleteTask': '刪除任務',
|
'deleteTask': '刪除任務',
|
||||||
'deleteTaskTip': '保留已經下載的文件',
|
'deleteTaskTip': '保留已經下載的檔案',
|
||||||
'delete': '刪除',
|
'delete': '刪除',
|
||||||
'newVersionTitle': '現新版本 @version 已發佈',
|
'newVersionTitle': '新版本 @version 已發佈',
|
||||||
'newVersionUpdate': '下載',
|
'newVersionUpdate': '下載',
|
||||||
'newVersionLater': '取消',
|
'newVersionLater': '取消',
|
||||||
'extensions': '擴充程序',
|
'extensions': '擴充程式',
|
||||||
'extensionInstallUrl': '安裝URL',
|
'extensionInstallUrl': '安裝連結',
|
||||||
'extensionInstallSuccess': '安裝成功',
|
'extensionInstallSuccess': '安裝成功',
|
||||||
'extensionUpdateSuccess': '更新完成',
|
'extensionUpdateSuccess': '更新完成',
|
||||||
'extensionDelete': '解除安裝',
|
'extensionDelete': '解除安裝',
|
||||||
'extensionAlreadyLatest': '已是最新版本',
|
'extensionAlreadyLatest': '已是最新版本',
|
||||||
'extensionFind': '取得擴充程序',
|
'extensionFind': '取得擴充程式',
|
||||||
'extensionDevelop': '開發擴充程序',
|
'extensionDevelop': '開發擴充程式',
|
||||||
'history': '歷史記錄',
|
'history': '歷史記錄',
|
||||||
'clearHistory': '清空記錄',
|
'clearHistory': '清空記錄',
|
||||||
'noHistoryFound': '還沒有記錄',
|
'noHistoryFound': '還沒有記錄',
|
||||||
@@ -77,10 +80,14 @@ const zhTW = {
|
|||||||
'serviceText': '執行中',
|
'serviceText': '執行中',
|
||||||
'network': '網路',
|
'network': '網路',
|
||||||
'proxy': '代理',
|
'proxy': '代理',
|
||||||
|
'noProxy': '不使用代理',
|
||||||
|
'systemProxy': '系統代理',
|
||||||
|
'customProxy': '自定義代理',
|
||||||
'server': '伺服器',
|
'server': '伺服器',
|
||||||
'username': '名稱',
|
'username': '名稱',
|
||||||
'password': '密碼',
|
'password': '密碼',
|
||||||
'thanks': '鳴謝',
|
'thanks': '感謝',
|
||||||
'thanksDesc': '感謝所有為 Gopeed 社群建設添磚加瓦的貢獻者們!'
|
'thanksDesc': '感謝所有為 Gopeed 社區建設添磚加瓦的貢獻者們!',
|
||||||
|
'browserExtension': '瀏覽器擴充程式',
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -6,6 +6,8 @@ import 'package:gopeed/i18n/langs/zh_tw.dart';
|
|||||||
import 'langs/en_us.dart';
|
import 'langs/en_us.dart';
|
||||||
import 'langs/ru_ru.dart';
|
import 'langs/ru_ru.dart';
|
||||||
import 'langs/zh_cn.dart';
|
import 'langs/zh_cn.dart';
|
||||||
|
import 'langs/vi_vn.dart';
|
||||||
|
import 'langs/tr_tr.dart';
|
||||||
|
|
||||||
final messages = _Messages();
|
final messages = _Messages();
|
||||||
|
|
||||||
@@ -19,5 +21,7 @@ class _Messages extends Translations {
|
|||||||
...zhTW,
|
...zhTW,
|
||||||
...faIR,
|
...faIR,
|
||||||
...jaJP,
|
...jaJP,
|
||||||
|
...viVN,
|
||||||
|
...trTR,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
@@ -7,13 +8,14 @@ import 'api/api.dart' as api;
|
|||||||
import 'app/modules/app/controllers/app_controller.dart';
|
import 'app/modules/app/controllers/app_controller.dart';
|
||||||
import 'app/modules/app/views/app_view.dart';
|
import 'app/modules/app/views/app_view.dart';
|
||||||
import 'core/libgopeed_boot.dart';
|
import 'core/libgopeed_boot.dart';
|
||||||
|
import 'database/database.dart';
|
||||||
|
import 'database/entity.dart';
|
||||||
import 'i18n/message.dart';
|
import 'i18n/message.dart';
|
||||||
import 'util/locale_manager.dart';
|
import 'util/locale_manager.dart';
|
||||||
import 'util/log_util.dart';
|
import 'util/log_util.dart';
|
||||||
import 'util/mac_secure_util.dart';
|
import 'util/mac_secure_util.dart';
|
||||||
import 'util/package_info.dart';
|
import 'util/package_info.dart';
|
||||||
import 'util/util.dart';
|
import 'util/util.dart';
|
||||||
import 'util/window_util.dart' as windows_util;
|
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
await init();
|
await init();
|
||||||
@@ -24,11 +26,13 @@ void main() async {
|
|||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await Util.initStorageDir();
|
||||||
|
await Database.instance.init();
|
||||||
if (Util.isDesktop()) {
|
if (Util.isDesktop()) {
|
||||||
await windowManager.ensureInitialized();
|
await windowManager.ensureInitialized();
|
||||||
final windowState = await windows_util.loadState();
|
final windowState = Database.instance.getWindowState();
|
||||||
final windowOptions = WindowOptions(
|
final windowOptions = WindowOptions(
|
||||||
size: Size(windowState.width, windowState.height),
|
size: Size(windowState?.width ?? 800, windowState?.height ?? 600),
|
||||||
center: true,
|
center: true,
|
||||||
skipTaskbar: false,
|
skipTaskbar: false,
|
||||||
);
|
);
|
||||||
@@ -44,17 +48,29 @@ Future<void> init() async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Util.isWeb()) {
|
|
||||||
await Util.initStorageDir();
|
|
||||||
}
|
|
||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
final controller = Get.put(AppController());
|
final controller = Get.put(AppController());
|
||||||
try {
|
try {
|
||||||
await controller.loadStartConfig();
|
await controller.loadStartConfig();
|
||||||
final startCfg = controller.startConfig.value;
|
final startCfg = controller.startConfig.value;
|
||||||
controller.runningPort.value = await LibgopeedBoot.instance.start(startCfg);
|
// When the app is closed by swiping on the mobile, the backend server is actually still running, don't need to start again.
|
||||||
api.init(startCfg.network, controller.runningAddress(), startCfg.apiToken);
|
final isRunning =
|
||||||
|
Util.isMobile() && (await FlutterForegroundTask.isRunningService);
|
||||||
|
if (!isRunning) {
|
||||||
|
controller.runningPort.value =
|
||||||
|
await LibgopeedBoot.instance.start(startCfg);
|
||||||
|
api.init(
|
||||||
|
startCfg.network, controller.runningAddress(), startCfg.apiToken);
|
||||||
|
Database.instance.saveLastRunningConfig(StartConfigEntity(
|
||||||
|
network: startCfg.network,
|
||||||
|
address: controller.runningAddress(),
|
||||||
|
apiToken: startCfg.apiToken));
|
||||||
|
} else {
|
||||||
|
final lastRunningConfig = Database.instance.getLastRunningConfig()!;
|
||||||
|
api.init(lastRunningConfig.network, lastRunningConfig.address,
|
||||||
|
lastRunningConfig.apiToken);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.e("libgopeed init fail", e);
|
logger.e("libgopeed init fail", e);
|
||||||
}
|
}
|
||||||
@@ -74,9 +90,6 @@ Future<void> init() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onStart() async {
|
Future<void> onStart() async {
|
||||||
final appController = Get.find<AppController>();
|
|
||||||
await appController.trackerUpdateOnStart();
|
|
||||||
|
|
||||||
// if is debug mode, check language message is complete,change debug locale to your comfortable language if you want
|
// if is debug mode, check language message is complete,change debug locale to your comfortable language if you want
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
final debugLang = getLocaleKey(debugLocale);
|
final debugLang = getLocaleKey(debugLocale);
|
||||||
|
|||||||
@@ -1,33 +1,29 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:macos_secure_bookmarks/macos_secure_bookmarks.dart';
|
import 'package:macos_secure_bookmarks/macos_secure_bookmarks.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
|
import '../database/database.dart';
|
||||||
import 'util.dart';
|
import 'util.dart';
|
||||||
|
|
||||||
class MacSecureUtil {
|
class MacSecureUtil {
|
||||||
static const _bookmarkKey = "bookmark:";
|
|
||||||
|
|
||||||
static Future<void> saveBookmark(String dir) async {
|
static Future<void> saveBookmark(String dir) async {
|
||||||
if (!Util.isMacos()) {
|
if (!Util.isMacos()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final secureBookmarks = SecureBookmarks();
|
final secureBookmarks = SecureBookmarks();
|
||||||
final bookmark = await secureBookmarks.bookmark(Directory(dir));
|
final bookmark = await secureBookmarks.bookmark(Directory(dir));
|
||||||
final prefs = await SharedPreferences.getInstance();
|
Database.instance.saveBookmark(MapEntry(dir, bookmark));
|
||||||
await prefs.setString(_bookmarkKey + dir, bookmark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> loadBookmark() async {
|
static Future<void> loadBookmark() async {
|
||||||
if (!Util.isMacos()) {
|
if (!Util.isMacos()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final prefs = await SharedPreferences.getInstance();
|
|
||||||
final keys = prefs.getKeys();
|
|
||||||
final secureBookmarks = SecureBookmarks();
|
final secureBookmarks = SecureBookmarks();
|
||||||
keys.where((k) => k.startsWith(_bookmarkKey)).forEach((k) async {
|
final bookmark = Database.instance.getBookmark() ?? {};
|
||||||
final resolvedFile = await secureBookmarks
|
bookmark.forEach((_, v) async {
|
||||||
.resolveBookmark(prefs.getString(k)!, isDirectory: true);
|
final resolvedFile =
|
||||||
|
await secureBookmarks.resolveBookmark(v, isDirectory: true);
|
||||||
await secureBookmarks.startAccessingSecurityScopedResource(resolvedFile);
|
await secureBookmarks.startAccessingSecurityScopedResource(resolvedFile);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,12 +50,11 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> initStorageDir() async {
|
static Future<void> initStorageDir() async {
|
||||||
var storageDir = "./";
|
var storageDir = "";
|
||||||
if (Platform.isAndroid) {
|
if (Util.isWindows()) {
|
||||||
storageDir = (await getExternalStorageDirectory())?.path ?? storageDir;
|
storageDir = "./";
|
||||||
} else if (Platform.isIOS) {
|
} else if (!Util.isWeb()) {
|
||||||
storageDir = (await getLibraryDirectory()).path;
|
if (Util.isLinux()) {
|
||||||
} else if (Util.isLinux()) {
|
|
||||||
storageDir = File(Platform.resolvedExecutable).parent.path;
|
storageDir = File(Platform.resolvedExecutable).parent.path;
|
||||||
// check has write permission, if not, fallback to application support dir
|
// check has write permission, if not, fallback to application support dir
|
||||||
try {
|
try {
|
||||||
@@ -65,6 +64,9 @@ class Util {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
storageDir = (await getApplicationSupportDirectory()).path;
|
storageDir = (await getApplicationSupportDirectory()).path;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
storageDir = (await getApplicationSupportDirectory()).path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_storageDir = storageDir;
|
_storageDir = storageDir;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
class WindowState {
|
|
||||||
late bool isMaximized;
|
|
||||||
late double width;
|
|
||||||
late double height;
|
|
||||||
|
|
||||||
WindowState(this.isMaximized, this.width, this.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
const String _windowStateIsMaximized = "window.isMaximized";
|
|
||||||
const String _windowStateWidth = "window.width";
|
|
||||||
const String _windowStateHeight = "window.height";
|
|
||||||
|
|
||||||
/// Save window state to storage.
|
|
||||||
void saveState({bool? isMaximized, double? width, double? height}) async {
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
|
||||||
if (isMaximized != null) {
|
|
||||||
await prefs.setBool(_windowStateIsMaximized, isMaximized);
|
|
||||||
}
|
|
||||||
if (width != null) {
|
|
||||||
await prefs.setDouble(_windowStateWidth, width);
|
|
||||||
}
|
|
||||||
if (height != null) {
|
|
||||||
await prefs.setDouble(_windowStateHeight, height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load window state from storage.
|
|
||||||
Future<WindowState> loadState() async {
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
|
||||||
return WindowState(
|
|
||||||
prefs.getBool(_windowStateIsMaximized) ?? false,
|
|
||||||
prefs.getDouble(_windowStateWidth) ?? 800,
|
|
||||||
prefs.getDouble(_windowStateHeight) ?? 600,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -13,8 +13,8 @@ essential: false
|
|||||||
icon: assets/icon/icon.svg
|
icon: assets/icon/icon.svg
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
- libappindicator3-1 | libayatana-appindicator3-1
|
- libayatana-appindicator3-1
|
||||||
- gir1.2-appindicator3-0.1 | gir1.2-ayatanaappindicator3-0.1
|
- gir1.2-ayatanaappindicator3-0.1
|
||||||
|
|
||||||
keywords:
|
keywords:
|
||||||
- Application
|
- Application
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
display_name: Gopeed
|
|
||||||
icon: assets/icon/icon.svg
|
|
||||||
summary: A modern download manager that supports all platforms. Built with Golang and Flutter.
|
|
||||||
group: Applications/Internet
|
|
||||||
vendor: monkeyWie
|
|
||||||
packager: madoka773
|
|
||||||
packagerEmail: [email protected]
|
|
||||||
license: GPL-3.0-or-later
|
|
||||||
url: https://github.com/GopeedLab/gopeed
|
|
||||||
|
|
||||||
description: A modern download manager that supports all platforms. Built with Golang and Flutter.
|
|
||||||
keywords:
|
|
||||||
- Application
|
|
||||||
- DownloadManager
|
|
||||||
- Network
|
|
||||||
- Utility
|
|
||||||
|
|
||||||
generic_name: Download Manager
|
|
||||||
|
|
||||||
categories:
|
|
||||||
- Network
|
|
||||||
- Utility
|
|
||||||
|
|
||||||
startup_notify: true
|
|
||||||
@@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||||
# Read more about iOS versioning at
|
# Read more about iOS versioning at
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
version: 1.5.3+1
|
version: 1.5.6+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.0.0 <4.0.0'
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
@@ -44,9 +44,8 @@ dependencies:
|
|||||||
path_provider: ^2.1.1
|
path_provider: ^2.1.1
|
||||||
file_picker: 5.3.1
|
file_picker: 5.3.1
|
||||||
macos_secure_bookmarks: ^0.2.1
|
macos_secure_bookmarks: ^0.2.1
|
||||||
rounded_loading_button: ^2.1.0
|
rounded_loading_button_plus: ^3.0.1
|
||||||
url_launcher: ^6.1.6
|
url_launcher: ^6.1.6
|
||||||
shared_preferences: ^2.2.0
|
|
||||||
logger: ^1.3.0
|
logger: ^1.3.0
|
||||||
desktop_drop: ^0.4.3
|
desktop_drop: ^0.4.3
|
||||||
package_info_plus: ^4.0.0
|
package_info_plus: ^4.0.0
|
||||||
@@ -64,6 +63,7 @@ dependencies:
|
|||||||
open_filex: ^4.3.4
|
open_filex: ^4.3.4
|
||||||
tray_manager: ^0.2.1
|
tray_manager: ^0.2.1
|
||||||
lecle_downloads_path_provider: ^0.0.2+8
|
lecle_downloads_path_provider: ^0.0.2+8
|
||||||
|
hive: ^2.2.3
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||