mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-12 11:24:08 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93614d46a8 | ||
|
|
04b0e691eb | ||
|
|
7f08fa0b23 | ||
|
|
df6a51d23c | ||
|
|
46c379d556 | ||
|
|
46cd9f7a3e | ||
|
|
5c2f66f4b6 | ||
|
|
cfdcb586ee | ||
|
|
55e6bdc4f7 | ||
|
|
b31b42301e | ||
|
|
7ce0d876b0 | ||
|
|
2fd2596aa0 | ||
|
|
e0973e4a34 | ||
|
|
4f7b8a05ad | ||
|
|
2927d1ef2b | ||
|
|
3451f577ab | ||
|
|
06671be0d8 | ||
|
|
8ae9363f0f | ||
|
|
5d84445f8f | ||
|
|
7c541e4047 | ||
|
|
3262e5a11b | ||
|
|
ff43a373cd | ||
|
|
7394d948e4 | ||
|
|
5afb3aa43b | ||
|
|
7705af6e68 | ||
|
|
684e060ef3 | ||
|
|
0c67792441 | ||
|
|
b0ef2c2a87 | ||
|
|
1977c2a0fc | ||
|
|
d289708f9e | ||
|
|
cd5fd45667 | ||
|
|
50bc9ab129 | ||
|
|
bfad91dcab | ||
|
|
61a959adda | ||
|
|
f4b839fd11 | ||
|
|
969aeb5e0a | ||
|
|
68d42eb397 | ||
|
|
08603f9510 | ||
|
|
b450bf67bd | ||
|
|
03e26dbea8 | ||
|
|
046a3ac9f9 | ||
|
|
9c5aebaf36 | ||
|
|
a094715d69 | ||
|
|
69bb875172 | ||
|
|
589f10c7ef | ||
|
|
654e57e946 | ||
|
|
b94b99ae09 | ||
|
|
fba990a056 | ||
|
|
cb07ce58bc | ||
|
|
50beef7b08 | ||
|
|
bd39e4110f | ||
|
|
86efcb98c5 | ||
|
|
f3d9873395 | ||
|
|
ef228c1722 | ||
|
|
6863317e9d | ||
|
|
2b83a735cb | ||
|
|
447f599783 | ||
|
|
f986f6253d | ||
|
|
2e1b621250 | ||
|
|
d50947b2e6 | ||
|
|
520a72415c | ||
|
|
a372b67edb | ||
|
|
2d86b5c132 | ||
|
|
63b3144633 | ||
|
|
1b0178fed9 | ||
|
|
83febe0a00 | ||
|
|
987580d400 | ||
|
|
0919936050 | ||
|
|
acc7ed8f6b | ||
|
|
ccb3267fba | ||
|
|
1249493a8a | ||
|
|
107141bbe7 | ||
|
|
b329fee107 | ||
|
|
3ce95f21fd | ||
|
|
f54ed5df5a | ||
|
|
727b7edb84 | ||
|
|
f5891ee03d | ||
|
|
724276ac69 | ||
|
|
a3f559c8e5 | ||
|
|
edd189a8a8 | ||
|
|
c970378fd7 | ||
|
|
8b61343aef | ||
|
|
2cb93a03e2 | ||
|
|
81dfc073a6 | ||
|
|
427921ccab | ||
|
|
f4876c8a0e | ||
|
|
35a3625b11 | ||
|
|
dc9b501e35 | ||
|
|
85fe92a378 | ||
|
|
983d9ad09e | ||
|
|
d9f757aaf0 | ||
|
|
cd409fcfb9 | ||
|
|
366244fa5d | ||
|
|
7a2e9b4fd1 | ||
|
|
203385d3f8 | ||
|
|
aaf73dec24 | ||
|
|
2523282a89 | ||
|
|
3384f5197a | ||
|
|
cd77665f02 | ||
|
|
a22b431150 | ||
|
|
eb7c9ad7f2 | ||
|
|
ea11fc38f1 | ||
|
|
1be16e9f2c | ||
|
|
1d86d14a20 | ||
|
|
5ad15cc4ac | ||
|
|
49604966fd | ||
|
|
bdb8ed177f | ||
|
|
2dc7048cba | ||
|
|
d3750464aa | ||
|
|
5c9bcd3731 | ||
|
|
bdda550b2c | ||
|
|
3308d966f0 | ||
|
|
18041ed9ec | ||
|
|
56b85e545e | ||
|
|
c5af916952 | ||
|
|
a1981328aa | ||
|
|
51244133e0 | ||
|
|
0c17093b1a | ||
|
|
6538b29b62 | ||
|
|
81e90e6b89 | ||
|
|
4f39296664 | ||
|
|
ece5b91dc2 | ||
|
|
d9f04ae928 | ||
|
|
e3ccecbd9c | ||
|
|
fb1c2cb060 | ||
|
|
9bff75464d | ||
|
|
863f759248 | ||
|
|
f89fb5e438 | ||
|
|
7ca1cc8c64 | ||
|
|
1f791c66e6 | ||
|
|
4d60c47d39 | ||
|
|
3fd3dd49d2 | ||
|
|
d119de7b98 | ||
|
|
69b359a9c9 | ||
|
|
4fbe13a1f0 | ||
|
|
3b50465708 | ||
|
|
473c58796c | ||
|
|
fab8f135f3 | ||
|
|
0fca7b6bc7 | ||
|
|
4700d0ba28 | ||
|
|
6e31ea089f | ||
|
|
4a2088f6fb | ||
|
|
17c8fb7e4d | ||
|
|
8c99bbc847 | ||
|
|
06c7fe7a22 | ||
|
|
8b3b5d4394 | ||
|
|
2ee73ab619 | ||
|
|
15413dbc95 | ||
|
|
c7c43fac80 | ||
|
|
4283bdfa5a | ||
|
|
328ba8592c | ||
|
|
a191a4140d | ||
|
|
3521837964 | ||
|
|
b30cd78f86 | ||
|
|
0583e4aaa6 | ||
|
|
a89c55b5c4 | ||
|
|
68c40d7f3f | ||
|
|
42a0b89d95 | ||
|
|
1860f534cd | ||
|
|
5c2d2ad7b4 | ||
|
|
db6352ada8 | ||
|
|
d1a5ed8b3d | ||
|
|
be9583be0f | ||
|
|
d2c70b077b | ||
|
|
53b3eea4fc | ||
|
|
54347f41b6 | ||
|
|
cea454b015 | ||
|
|
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 | ||
|
|
abccbabc78 | ||
|
|
c26eb26b8f | ||
|
|
74beea6044 | ||
|
|
e548d7e0c9 | ||
|
|
a996d57914 | ||
|
|
f7dc60ad50 | ||
|
|
8425a96ac9 | ||
|
|
99f4e8c895 | ||
|
|
cc0f61b527 | ||
|
|
922ef969a6 | ||
|
|
3a542054fc | ||
|
|
895a8d2ee4 | ||
|
|
29d0f5ebcf | ||
|
|
31228e3edf | ||
|
|
31a32d7e14 | ||
|
|
65fd6fb489 | ||
|
|
953b878a89 | ||
|
|
ae4ca3da58 | ||
|
|
d09bd180af | ||
|
|
3d24e353c5 | ||
|
|
ce7489b0c0 | ||
|
|
2b5091ba21 | ||
|
|
ff32971aca | ||
|
|
f2af61f9aa | ||
|
|
d935b9d631 | ||
|
|
ae66d1d83d | ||
|
|
aa91ca1d50 | ||
|
|
2d4bdea5cb | ||
|
|
2f2393ac20 | ||
|
|
5a761e244a | ||
|
|
6538766780 | ||
|
|
16b7a3d5b3 | ||
|
|
ef97528114 | ||
|
|
b58669bb46 | ||
|
|
51d28c5e53 | ||
|
|
db15650664 | ||
|
|
ee7da179c1 | ||
|
|
6bb32372ab | ||
|
|
7d6428c967 | ||
|
|
bba5107dd5 | ||
|
|
ddfe76b635 | ||
|
|
aad7395dde | ||
|
|
6f541715df | ||
|
|
848797b2fd | ||
|
|
0a05bf41e7 | ||
|
|
485656d1d4 | ||
|
|
c074e0c2bc | ||
|
|
0db0a2c987 | ||
|
|
b06a79b5c7 | ||
|
|
4840c4b8a4 | ||
|
|
e72b097aa2 | ||
|
|
af52c4ce7e | ||
|
|
aae79c2449 | ||
|
|
83838afce9 | ||
|
|
4690107e32 | ||
|
|
74b08b3631 | ||
|
|
953d348c0c | ||
|
|
00cea68b6e | ||
|
|
daa9d4c707 | ||
|
|
6bc587752a | ||
|
|
11befc09bd | ||
|
|
ff6c0da262 | ||
|
|
aab4a37a7e | ||
|
|
74c9491893 | ||
|
|
256faf2cbd | ||
|
|
32e3620f5e | ||
|
|
39202b44a1 | ||
|
|
457d9e85d6 | ||
|
|
858ad74339 | ||
|
|
755d7ce814 | ||
|
|
854f600d3f |
No files matched your search
@@ -0,0 +1,16 @@
|
|||||||
|
.git
|
||||||
|
|
||||||
|
*.data
|
||||||
|
*.log
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
**/node_modules
|
||||||
|
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
.github
|
||||||
|
_docs
|
||||||
|
_examples
|
||||||
|
bin
|
||||||
|
ui
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
* @monkeyWie
|
||||||
+167
-21
@@ -1,35 +1,181 @@
|
|||||||
name-template: 'v$NEXT_PATCH_VERSION 🌈'
|
name-template: "v$NEXT_PATCH_VERSION 🌈"
|
||||||
tag-template: 'v$NEXT_PATCH_VERSION'
|
tag-template: "v$NEXT_PATCH_VERSION"
|
||||||
categories:
|
categories:
|
||||||
- title: '🆕 Features'
|
- title: "🆕 Features"
|
||||||
labels:
|
labels:
|
||||||
- 'feat'
|
- "feat"
|
||||||
- 'feature'
|
- "feature"
|
||||||
- 'enhancement'
|
- "enhancement"
|
||||||
- title: '🐛 Bug Fixes'
|
- title: "🐛 Bug Fixes"
|
||||||
labels:
|
labels:
|
||||||
- 'fix'
|
- "fix"
|
||||||
- 'bugfix'
|
- "bugfix"
|
||||||
- 'bug'
|
- "bug"
|
||||||
- title: '🧰 Maintenance'
|
- title: "🔧 Performance Improvements"
|
||||||
label: 'chore'
|
labels:
|
||||||
- title: '📖 Document'
|
- "perf"
|
||||||
label: 'doc'
|
- title: "🧪 Tests"
|
||||||
- title: '🚀 CI/CD'
|
label: "test"
|
||||||
label: 'ci'
|
- title: "🧰 Maintenance"
|
||||||
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
|
label: "chore"
|
||||||
|
- title: "📖 Document"
|
||||||
|
label: "docs"
|
||||||
|
- title: "🚀 CI/CD"
|
||||||
|
label: "ci"
|
||||||
|
- title: "🌎 Internationalization"
|
||||||
|
label: "translation"
|
||||||
|
change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
|
||||||
version-resolver:
|
version-resolver:
|
||||||
major:
|
major:
|
||||||
labels:
|
labels:
|
||||||
- 'major'
|
- "major"
|
||||||
minor:
|
minor:
|
||||||
labels:
|
labels:
|
||||||
- 'minor'
|
- "minor"
|
||||||
patch:
|
patch:
|
||||||
labels:
|
labels:
|
||||||
- 'patch'
|
- "patch"
|
||||||
default: patch
|
default: patch
|
||||||
template: |
|
template: |
|
||||||
## Changes
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">🪟 Windows</td>
|
||||||
|
<td><code>EXE</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-windows-amd64-portable.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">🍎 MacOS</td>
|
||||||
|
<td rowspan="3"><code>DMG</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-macos.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-macos-amd64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-macos-arm64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">🐧 Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>DEB</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-linux-amd64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-linux-arm64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>AppImage</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-linux-amd64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-linux-arm64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">🤖 Android</td>
|
||||||
|
<td rowspan="4"><code>APK</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-android.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>armeabi-v7a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-android-armeabi-v7a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64-v8a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-android-arm64-v8a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x86_64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-android-x86_64.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>📱 iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-v$NEXT_PATCH_VERSION-ios.ipa">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>🐳 Docker</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">💾 Qnap</td>
|
||||||
|
<td rowspan="2"><code>QPKG</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-v$NEXT_PATCH_VERSION-qnap-amd64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-v$NEXT_PATCH_VERSION-qnap-arm64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">🌐 Web</td>
|
||||||
|
<td rowspan="3"><code>Windows</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-windows-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-windows-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>MacOS</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-macos-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-macos-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3"><code>Linux</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-linux-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-linux-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-v$NEXT_PATCH_VERSION-linux-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
# Release notes
|
||||||
|
|
||||||
|
$CHANGES
|
||||||
|
|
||||||
|
# 更新日志
|
||||||
|
|
||||||
$CHANGES
|
$CHANGES
|
||||||
+391
-108
File diff suppressed because it is too large.
Load diff
@@ -17,7 +17,7 @@ on:
|
|||||||
- "Dockerfile"
|
- "Dockerfile"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: "1.19"
|
GO_VERSION: "1.24"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
+106
-12
@@ -27,8 +27,8 @@ on:
|
|||||||
- "go.sum"
|
- "go.sum"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: "1.19"
|
GO_VERSION: "1.24"
|
||||||
FLUTTER_VERSION: "3.10.6"
|
FLUTTER_VERSION: "3.24.5"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# lint:
|
# lint:
|
||||||
@@ -53,14 +53,56 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ${{ env.GO_VERSION }}
|
go-version: ${{ env.GO_VERSION }}
|
||||||
- name: Run Unit tests.
|
- name: Run Unit tests.
|
||||||
run: go test $(go list ./... | grep -v /cmd/ | grep -v /bind/ ) -v -covermode=count -coverprofile=coverage.txt
|
run: |
|
||||||
- uses: codecov/codecov-action@v3
|
# Get packages for testing and coverage (including cmd/web for flags_test.go)
|
||||||
|
PACKAGES=$(go list ./... | grep -v /bind/ | grep -v -E '/cmd/(?!web)')
|
||||||
|
go test -v -coverpkg=$(echo "$PACKAGES" | paste -sd "," -) -covermode=count -coverprofile=coverage.txt $PACKAGES
|
||||||
|
# Filter out main.go from coverage report to avoid lowering coverage percentage
|
||||||
|
grep -v "main.go" coverage.txt > coverage_filtered.txt || true
|
||||||
|
mv coverage_filtered.txt coverage.txt
|
||||||
|
- uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
files: ./coverage.txt
|
files: ./coverage.txt
|
||||||
build:
|
token: ${{ secrets.CODECOV_UPLOAD_TOKEN }}
|
||||||
name: Build check
|
build-desktop:
|
||||||
runs-on: ubuntu-latest
|
name: Build desktop check
|
||||||
# needs: [lint, test]
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [windows-latest, macos-latest, ubuntu-24.04, ubuntu-24.04-arm]
|
||||||
|
needs: [test]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
|
channel: master
|
||||||
|
- if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
- if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
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
|
||||||
|
- if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y ninja-build libgtk-3-dev libayatana-appindicator3-dev
|
||||||
|
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
|
||||||
|
build-mobile:
|
||||||
|
name: Build mobile check
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macos-14, ubuntu-latest]
|
||||||
needs: [test]
|
needs: [test]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -71,10 +113,62 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
- run: |
|
- run: |
|
||||||
sudo apt-get update -y
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
sudo apt-get install -y ninja-build libgtk-3-dev libayatana-appindicator3-dev
|
go get golang.org/x/mobile/bind
|
||||||
|
gomobile init
|
||||||
|
- if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
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 ipa --no-codesign
|
||||||
|
- if: runner.os == 'Linux'
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: "zulu"
|
||||||
|
java-version: "17"
|
||||||
|
- if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
gomobile bind -tags nosqlite -ldflags="-w -s -checklinkname=0" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg=com.gopeed github.com/GopeedLab/gopeed/bind/mobile
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build apk
|
||||||
|
|
||||||
|
build-web:
|
||||||
|
name: Build web check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
- name: Build
|
- name: Build
|
||||||
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
|
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build linux
|
flutter build web --no-web-resources-cdn
|
||||||
|
cd ../../
|
||||||
|
rm -rf cmd/web/dist
|
||||||
|
cp -r ui/flutter/build/web cmd/web/dist
|
||||||
|
go build -tags nosqlite,web -ldflags="-s -w" github.com/GopeedLab/gopeed/cmd/web
|
||||||
|
build-docker:
|
||||||
|
name: Build docker check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GO_VERSION }}
|
||||||
|
- uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd ui/flutter
|
||||||
|
flutter build web --no-web-resources-cdn
|
||||||
|
cd ../../
|
||||||
|
rm -rf cmd/web/dist
|
||||||
|
cp -r ui/flutter/build/web cmd/web/dist
|
||||||
|
docker build -t gopeed .
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
ui/flutter/dist/
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
|||||||
+2
-22
@@ -17,18 +17,11 @@ start the front-end flutter project in `debug` mode to run.
|
|||||||
|
|
||||||
## Translation
|
## Translation
|
||||||
|
|
||||||
The internationalization files of Gopeed are located in the `ui/flutter/assets/locales` directory.
|
The internationalization files of Gopeed are located in the `ui/flutter/lib/i18n/langs` directory.
|
||||||
You only need to add the corresponding language file in this directory.
|
You only need to add the corresponding language file in this directory.
|
||||||
|
|
||||||
|
|
||||||
Generate locales after you edit locales:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
get generate locales
|
|
||||||
```
|
|
||||||
|
|
||||||
Please refer to `en_us.dart` for translation.
|
Please refer to `en_us.dart` for translation.
|
||||||
|
words prefixed with `@` are not meant to be translated.
|
||||||
|
|
||||||
## flutter development
|
## flutter development
|
||||||
|
|
||||||
@@ -39,16 +32,3 @@ Turn on build_runner watcher if you want to edit api/models:
|
|||||||
```
|
```
|
||||||
flutter pub run build_runner watch
|
flutter pub run build_runner watch
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
get-cli commands usages:
|
|
||||||
|
|
||||||
```
|
|
||||||
create:
|
|
||||||
controller: Generate controller
|
|
||||||
page: Use to generate pages
|
|
||||||
view: Generate view
|
|
||||||
generate:
|
|
||||||
locales: Generate translation file from json files
|
|
||||||
model: generate Class model from json
|
|
||||||
```
|
|
||||||
+1
-22
@@ -17,17 +17,9 @@
|
|||||||
|
|
||||||
## 翻訳
|
## 翻訳
|
||||||
|
|
||||||
Gopeed の国際化ファイルは `ui/flutter/assets/locales` ディレクトリにあります。
|
Gopeed の国際化ファイルは `ui/flutter/lib/i18n/langs` ディレクトリにあります。
|
||||||
このディレクトリに対応する言語ファイルを追加するだけでよいです。
|
このディレクトリに対応する言語ファイルを追加するだけでよいです。
|
||||||
|
|
||||||
|
|
||||||
ロケール編集後にロケールを生成:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
get generate locales
|
|
||||||
```
|
|
||||||
|
|
||||||
翻訳については `en_us.dart` を参照してください。
|
翻訳については `en_us.dart` を参照してください。
|
||||||
|
|
||||||
## flutter での開発
|
## flutter での開発
|
||||||
@@ -39,16 +31,3 @@ api/models を編集したい場合は build_runner watcher をオンにしま
|
|||||||
```
|
```
|
||||||
flutter pub run build_runner watch
|
flutter pub run build_runner watch
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
get-cli コマンドの使用法:
|
|
||||||
|
|
||||||
```
|
|
||||||
create:
|
|
||||||
controller: Generate controller
|
|
||||||
page: Use to generate pages
|
|
||||||
view: Generate view
|
|
||||||
generate:
|
|
||||||
locales: Generate translation file from json files
|
|
||||||
model: generate Class model from json
|
|
||||||
```
|
|
||||||
@@ -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:
|
||||||
+2
-20
@@ -14,15 +14,9 @@ flutter 项目即可运行。
|
|||||||
|
|
||||||
## 翻译
|
## 翻译
|
||||||
|
|
||||||
Gopeed 的国际化文件位于 `ui/flutter/assets/locales` 目录下,只需要在该目录下添加对应的语言文件即可。
|
Gopeed 的国际化文件位于 `ui/flutter/lib/i18n/langs` 目录下,只需要在该目录下添加对应的语言文件即可。
|
||||||
|
|
||||||
编辑locales后请运行以下命令:
|
请注意以 `en_us.dart` 为参照进行翻译。
|
||||||
|
|
||||||
```
|
|
||||||
get generate locales
|
|
||||||
```
|
|
||||||
|
|
||||||
请注意以 `en_US.json` 为参照进行翻译。
|
|
||||||
|
|
||||||
## flutter开发
|
## flutter开发
|
||||||
|
|
||||||
@@ -34,15 +28,3 @@ get generate locales
|
|||||||
flutter pub run build_runner watch
|
flutter pub run build_runner watch
|
||||||
```
|
```
|
||||||
|
|
||||||
适用get-cli 命令:
|
|
||||||
|
|
||||||
```
|
|
||||||
create:
|
|
||||||
controller: Generate controller
|
|
||||||
page: Use to generate pages
|
|
||||||
view: Generate view
|
|
||||||
generate:
|
|
||||||
locales: Generate translation file from json files
|
|
||||||
model: generate Class model from json
|
|
||||||
```
|
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Gopeed 協助指南
|
||||||
|
|
||||||
|
首先感謝您願意幫助我們改進並優化該項目,這份指南將會幫助您更好的參與 Gopeed 的開發。
|
||||||
|
|
||||||
|
## 分支說明
|
||||||
|
|
||||||
|
本項目只有一個分支,即 `main` 分支,如果您想要參與 Gopeed 的開發,請先 fork 該項目,再在您自己的 fork 中進行開發,開發完成後再開啟PR,以合併至 `main` 分支。
|
||||||
|
|
||||||
|
## 離線開發
|
||||||
|
|
||||||
|
建議使用 web 端進行開發與調試,首先啟動服務,使用指令 `go run cmd/api/main.go` 啟動 ,該服務默認連接埠為 `9999`,接著以 `debug` 模式啟動前端 flutter 項目即可。
|
||||||
|
|
||||||
|
## 翻譯
|
||||||
|
|
||||||
|
Gopeed 的翻譯文件位於 `ui/flutter/lib/i18n/langs` 目錄中,只需要修改或新建翻譯文件即可。
|
||||||
|
|
||||||
|
|
||||||
|
請以 `en_us.dart` 作為參照。
|
||||||
|
|
||||||
|
## flutter開發
|
||||||
|
|
||||||
|
每次提交PR前請務必執行 `dart format ./ui/flutter`
|
||||||
|
|
||||||
|
如果需要編輯 api/models,請打開build_runner watcher:
|
||||||
|
|
||||||
|
```
|
||||||
|
flutter pub run build_runner watch
|
||||||
|
```
|
||||||
+14
-12
@@ -1,21 +1,23 @@
|
|||||||
FROM instrumentisto/flutter:3.10.6 AS flutter
|
FROM golang:1.23.3 AS go
|
||||||
WORKDIR /app
|
|
||||||
COPY ./ui/flutter/pubspec.yaml ./ui/flutter/pubspec.lock ./
|
|
||||||
RUN flutter pub get
|
|
||||||
COPY ./ui/flutter ./
|
|
||||||
RUN flutter build web --web-renderer html
|
|
||||||
|
|
||||||
FROM golang:1.19.3 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
|
ARG VERSION=dev
|
||||||
RUN CGO_ENABLED=0 go build -tags nosqlite,web -ldflags="-s -w" -o dist/gopeed github.com/GopeedLab/gopeed/cmd/web
|
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.18
|
||||||
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 add --no-cache su-exec ; \
|
||||||
|
chmod +x ./entrypoint.sh && \
|
||||||
|
rm -rf /var/cache/apk/*
|
||||||
|
VOLUME ["/app/storage"]
|
||||||
|
ENV PUID=0 PGID=0 UMASK=022
|
||||||
EXPOSE 9999
|
EXPOSE 9999
|
||||||
ENTRYPOINT ["./gopeed"]
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# [](https://gopeed.com)
|
||||||
|
|
||||||
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
||||||
[](https://codecov.io/gh/GopeedLab/gopeed)
|
[](https://codecov.io/gh/GopeedLab/gopeed)
|
||||||
[](https://github.com/GopeedLab/gopeed/releases)
|
[](https://github.com/GopeedLab/gopeed/releases)
|
||||||
@@ -5,35 +7,158 @@
|
|||||||
[](https://docs.gopeed.com/donate.html)
|
[](https://docs.gopeed.com/donate.html)
|
||||||
[](https://discord.gg/ZUJqJrwCGB)
|
[](https://discord.gg/ZUJqJrwCGB)
|
||||||
|
|
||||||

|
<a href="https://trendshift.io/repositories/7953" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7953" alt="GopeedLab%2Fgopeed | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.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.
|
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) | 📖 [Develop Docs](https://docs.gopeed.com)
|
Visit ✈ [Official Website](https://gopeed.com) | 📖 [Official Docs](https://docs.gopeed.com)
|
||||||
|
|
||||||
## Install
|
## ⬇️ Download
|
||||||
|
|
||||||
**Supported platforms**
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">🪟 Windows</td>
|
||||||
|
<td><code>EXE</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">🍎 MacOS</td>
|
||||||
|
<td rowspan="3"><code>DMG</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-amd64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-arm64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">🐧 Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>DEB</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>AppImage</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">🤖 Android</td>
|
||||||
|
<td rowspan="4"><code>APK</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>armeabi-v7a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-armeabi-v7a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64-v8a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-arm64-v8a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x86_64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-x86_64.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>📱 iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>🐳 Docker</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">💾 Qnap</td>
|
||||||
|
<td rowspan="2"><code>QPKG</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-amd64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-arm64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">🌐 Web</td>
|
||||||
|
<td rowspan="3"><code>Windows</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>MacOS</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3"><code>Linux</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-386.zip">📥</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)
|
### 🛠️ Command tool
|
||||||
|
|
||||||
> Tips: If the macos open failed, please execute the `xattr -d com.apple.quarantine /Applications/Gopeed.app` command in the terminal
|
|
||||||
|
|
||||||
### Command tool
|
|
||||||
|
|
||||||
use `go install`:
|
use `go install`:
|
||||||
|
|
||||||
@@ -41,54 +166,40 @@ 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
|
## 💝 Donate
|
||||||
docker run -d -p 9999:9999 -v /path/to/download:/root/Downloads liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 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
|
|
||||||
|
|
||||||
If you like this project, please consider [donating](https://docs.gopeed.com/donate.html) to support the development of this project, thank you!
|
If you like this project, please consider [donating](https://docs.gopeed.com/donate.html) to support the development of this project, thank you!
|
||||||
|
|
||||||
## Showcase
|
## 🖼️ Showcase
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Development
|
## 👨💻 Development
|
||||||
|
|
||||||
This project is divided into two parts, the front end uses `flutter`, the back end uses `Golang`, and the two sides communicate through the `http` protocol. On the unix system, `unix socket` is used, and on the windows system, `tcp` protocol is used.
|
This project is divided into two parts, the front end uses `flutter`, the back end uses `Golang`, and the two sides communicate through the `http` protocol. On the unix system, `unix socket` is used, and on the windows system, `tcp` protocol is used.
|
||||||
|
|
||||||
> The front code is located in the `ui/flutter` directory.
|
> The front code is located in the `ui/flutter` directory.
|
||||||
|
|
||||||
### Environment
|
### 🌍 Environment
|
||||||
|
|
||||||
1. Golang 1.19+
|
1. Golang 1.23+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.24+
|
||||||
|
|
||||||
### Clone
|
### 📋 Clone
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone [email protected]:GopeedLab/gopeed.git
|
git clone [email protected]:GopeedLab/gopeed.git
|
||||||
```
|
```
|
||||||
|
|
||||||
### Contributing
|
### 🤝 Contributing
|
||||||
|
|
||||||
Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md)
|
Please refer to [CONTRIBUTING.md](/CONTRIBUTING.md)
|
||||||
|
|
||||||
### Build
|
### 🏗️ Build
|
||||||
|
|
||||||
#### Desktop
|
#### Desktop
|
||||||
|
|
||||||
@@ -135,7 +246,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 -checklinkname=0" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
@@ -159,21 +270,20 @@ cd ../../
|
|||||||
rm -rf cmd/web/dist
|
rm -rf cmd/web/dist
|
||||||
cp -r ui/flutter/build/web 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
|
go build -tags nosqlite,web -ldflags="-s -w" -o bin/ github.com/GopeedLab/gopeed/cmd/web
|
||||||
go run cmd/web/main.go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Credits
|
## ❤️ Credits
|
||||||
|
|
||||||
### Contributors
|
### 👥 Contributors
|
||||||
|
|
||||||
<a href="https://github.com/GopeedLab/gopeed/graphs/contributors">
|
<a href="https://github.com/GopeedLab/gopeed/graphs/contributors">
|
||||||
<img src="https://contrib.rocks/image?repo=GopeedLab/gopeed" />
|
<img src="https://contrib.rocks/image?repo=GopeedLab/gopeed" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
### JetBrains
|
### 🏢 JetBrains
|
||||||
|
|
||||||
[](https://www.jetbrains.com/?from=gopeed)
|
[](https://www.jetbrains.com/?from=gopeed)
|
||||||
|
|
||||||
## License
|
## 📄 License
|
||||||
|
|
||||||
[GPLv3](LICENSE)
|
[GPLv3](LICENSE)
|
||||||
+155
-56
@@ -1,3 +1,5 @@
|
|||||||
|
# [](https://gopeed.com)
|
||||||
|
|
||||||
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
||||||
[](https://codecov.io/gh/GopeedLab/gopeed)
|
[](https://codecov.io/gh/GopeedLab/gopeed)
|
||||||
[](https://github.com/GopeedLab/gopeed/releases)
|
[](https://github.com/GopeedLab/gopeed/releases)
|
||||||
@@ -5,90 +7,188 @@
|
|||||||
[](https://docs.gopeed.com/donate.html)
|
[](https://docs.gopeed.com/donate.html)
|
||||||
[](https://discord.gg/ZUJqJrwCGB)
|
[](https://discord.gg/ZUJqJrwCGB)
|
||||||
|
|
||||||

|
<a href="https://trendshift.io/repositories/7953" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7953" alt="GopeedLab%2Fgopeed | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md)
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
## はじめに
|
## 🚀 はじめに
|
||||||
|
|
||||||
Gopeed (正式名 Go Speed) は `Golang` + `Flutter` によって開発された高速ダウンローダーで、(HTTP、BitTorrent、Magnet) プロトコルをサポートし、すべてのプラットフォームをサポートします。
|
Gopeed (正式名 Go Speed) は `Golang` + `Flutter` によって開発された高速ダウンローダーで、(HTTP、BitTorrent、Magnet) プロトコルをサポートし、すべてのプラットフォームをサポートします。基本的なダウンロード機能に加え、[APIs](https://docs.gopeed.com/dev-api.html)との連動や[拡張機能](https://docs.gopeed.com/dev-extension.html)のインストール・開発による追加機能にも対応した、カスタマイズ性の高いダウンローダーです。
|
||||||
|
|
||||||
見て下さい ✈ [公式ウェブサイト](https://gopeed.com) | 📖 [開発ドキュメント](https://docs.gopeed.com)
|
見て下さい ✈ [公式ウェブサイト](https://gopeed.com) | 📖 [開発ドキュメント](https://docs.gopeed.com)
|
||||||
|
|
||||||
## インストール
|
## ⬇️ インストール
|
||||||
|
|
||||||
**サポートするプラットフォーム**
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">🪟 Windows</td>
|
||||||
|
<td><code>EXE</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">🍎 MacOS</td>
|
||||||
|
<td rowspan="3"><code>DMG</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-amd64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-arm64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">🐧 Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>DEB</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>AppImage</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">🤖 Android</td>
|
||||||
|
<td rowspan="4"><code>APK</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>armeabi-v7a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-armeabi-v7a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64-v8a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-arm64-v8a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x86_64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-x86_64.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>📱 iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>🐳 Docker</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">💾 Qnap</td>
|
||||||
|
<td rowspan="2"><code>QPKG</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-amd64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-arm64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">🌐 Web</td>
|
||||||
|
<td rowspan="3"><code>Windows</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>MacOS</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3"><code>Linux</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
インストールについての詳細は、[インストール](https://docs.gopeed.com/install.html)を参照してください。
|
||||||
|
|
||||||
- [x] windows
|
### 🛠️ コマンドツール
|
||||||
- [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` コマンドを実行してください
|
もしこのプロジェクトがお気に召しましたら、このプロジェクトの発展を支援するために[寄付](https://docs.gopeed.com/donate.html)をご検討ください!
|
||||||
|
|
||||||
### コマンドツール
|
## 🖼️ ショーケース
|
||||||
|
|
||||||
`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 liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Docker Compose の使用
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Gopeed へのアクセス
|
|
||||||
|
|
||||||
docker コンテナが起動しているときは、`http://localhost:9999` からウェブページにアクセスできます。
|
|
||||||
|
|
||||||
## 寄付
|
|
||||||
|
|
||||||
もしこのプロジェクトがお気に召しましたら、このプロジェクトの発展を支援するために[寄付](/.donate/index.md#donate)をご検討ください!
|
|
||||||
|
|
||||||
## ショーケース
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 開発
|
## 👨💻 開発
|
||||||
|
|
||||||
このプロジェクトは二つの部分に分かれており、フロントエンドでは `flutter` を、バックエンドでは `Golang` を使用し、両者は `http` プロトコルで通信する。ユニックスシステムでは `unix socket` を、ウィンドウズシステムでは `tcp` プロトコルを使用します。
|
このプロジェクトは二つの部分に分かれており、フロントエンドでは `flutter` を、バックエンドでは `Golang` を使用し、両者は `http` プロトコルで通信する。ユニックスシステムでは `unix socket` を、ウィンドウズシステムでは `tcp` プロトコルを使用します。
|
||||||
|
|
||||||
> フロントコードは `ui/flutter` ディレクトリにあります。
|
> フロントコードは `ui/flutter` ディレクトリにあります。
|
||||||
|
|
||||||
### 環境
|
### 🌍 環境
|
||||||
|
|
||||||
1. Go 言語 1.19+
|
1. Go 言語 1.23+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.24+
|
||||||
|
|
||||||
### クローン
|
### 📋 クローン
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone [email protected]:GopeedLab/gopeed.git
|
git clone [email protected]:GopeedLab/gopeed.git
|
||||||
```
|
```
|
||||||
|
|
||||||
### コントリビュート
|
### 🤝 コントリビュート
|
||||||
|
|
||||||
[CONTRIBUTING.md](/CONTRIBUTING_ja-JP.md) をご参照ください
|
[CONTRIBUTING.md](/CONTRIBUTING_ja-JP.md) をご参照ください
|
||||||
|
|
||||||
### ビルド
|
### 🏗️ ビルド
|
||||||
|
|
||||||
#### デスクトップ
|
#### デスクトップ
|
||||||
|
|
||||||
@@ -135,7 +235,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 -checklinkname=0" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
@@ -159,10 +259,9 @@ cd ../../
|
|||||||
rm -rf cmd/web/dist
|
rm -rf cmd/web/dist
|
||||||
cp -r ui/flutter/build/web 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
|
go build -tags nosqlite,web -ldflags="-s -w" -o bin/ github.com/GopeedLab/gopeed/cmd/web
|
||||||
go run cmd/web/main.go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 感謝
|
## ❤️ 感謝
|
||||||
|
|
||||||
### コントリビューター
|
### コントリビューター
|
||||||
|
|
||||||
|
|||||||
+284
@@ -0,0 +1,284 @@
|
|||||||
|
# [](https://gopeed.com)
|
||||||
|
|
||||||
|
[](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)
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/7953" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7953" alt="GopeedLab%2Fgopeed | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
[](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>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">🪟 Windows</td>
|
||||||
|
<td><code>EXE</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">🍎 MacOS</td>
|
||||||
|
<td rowspan="3"><code>DMG</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-amd64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-arm64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">🐧 Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>DEB</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>AppImage</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">🤖 Android</td>
|
||||||
|
<td rowspan="4"><code>APK</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>armeabi-v7a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-armeabi-v7a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64-v8a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-arm64-v8a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x86_64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-x86_64.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>📱 iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>🐳 Docker</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">💾 Qnap</td>
|
||||||
|
<td rowspan="2"><code>QPKG</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-amd64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-arm64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">🌐 Web</td>
|
||||||
|
<td rowspan="3"><code>Windows</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>MacOS</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3"><code>Linux</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-386.zip">📥</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)
|
||||||
|
|
||||||
|
### 🛠️ Công cụ lệnh
|
||||||
|
|
||||||
|
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.23+
|
||||||
|
2. Flutter 3.24+
|
||||||
|
|
||||||
|
### 📋 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 -checklinkname=0" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -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)
|
||||||
+157
-48
@@ -1,3 +1,5 @@
|
|||||||
|
# [](https://gopeed.com)
|
||||||
|
|
||||||
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
[](https://github.com/GopeedLab/gopeed/actions?query=workflow%3Atest)
|
||||||
[](https://codecov.io/gh/GopeedLab/gopeed)
|
[](https://codecov.io/gh/GopeedLab/gopeed)
|
||||||
[](https://github.com/GopeedLab/gopeed/releases)
|
[](https://github.com/GopeedLab/gopeed/releases)
|
||||||
@@ -5,35 +7,157 @@
|
|||||||
[](https://docs.gopeed.com/zh/donate.html)
|
[](https://docs.gopeed.com/zh/donate.html)
|
||||||
[](https://discord.gg/ZUJqJrwCGB)
|
[](https://discord.gg/ZUJqJrwCGB)
|
||||||
|
|
||||||

|
<a href="https://trendshift.io/repositories/7953" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7953" alt="GopeedLab%2Fgopeed | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
[](https://ko-fi.com/R6R6IJGN6)
|
[](https://ko-fi.com/R6R6IJGN6)
|
||||||
|
|
||||||
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md)
|
[English](/README.md) | [中文](/README_zh-CN.md) | [日本語](/README_ja-JP.md) | [正體中文](/README_zh-TW.md) | [Tiếng Việt](/README_vi-VN.md)
|
||||||
|
|
||||||
## 介绍
|
## 🚀 介绍
|
||||||
|
|
||||||
Gopeed(全称 Go Speed),是一款由`Golang`+`Flutter`开发的高速下载器,支持(HTTP、BitTorrent、Magnet)协议下载,并且支持全平台使用。
|
Gopeed(全称 Go Speed),直译过来中文名叫做`够快下载器`(不是狗屁下载器!),是一款由`Golang`+`Flutter`开发的高速下载器,支持(HTTP、BitTorrent、Magnet)协议下载,并且支持全平台使用。除了基本的下载功能外,Gopeed 还是一款高度可定制化的下载器,支持通过对接[APIs](https://docs.gopeed.com/zh/dev-api.html)或者安装和开发[扩展](https://docs.gopeed.com/zh/dev-extension.html)来实现更多的功能。
|
||||||
|
|
||||||
访问 ✈ [官方网站](https://gopeed.com/zh-CN) | 📖 [开发文档](https://docs.gopeed.com/zh/)
|
访问 ✈ [官方网站](https://gopeed.com/zh-CN) | 📖 [官方文档](https://docs.gopeed.com/zh/)
|
||||||
|
|
||||||
## 安装
|
## ⬇️ 下载
|
||||||
|
|
||||||
**已支持平台**
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">🪟 Windows</td>
|
||||||
|
<td><code>EXE</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">🍎 MacOS</td>
|
||||||
|
<td rowspan="3"><code>DMG</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-amd64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-arm64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">🐧 Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>DEB</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>AppImage</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">🤖 Android</td>
|
||||||
|
<td rowspan="4"><code>APK</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>armeabi-v7a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-armeabi-v7a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64-v8a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-arm64-v8a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x86_64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-x86_64.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>📱 iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>🐳 Docker</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">💾 Qnap</td>
|
||||||
|
<td rowspan="2"><code>QPKG</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-amd64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-arm64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">🌐 Web</td>
|
||||||
|
<td rowspan="3"><code>Windows</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>MacOS</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3"><code>Linux</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
更多关于安装的内容请参考[安装文档](https://docs.gopeed.com/zh/install.html)
|
||||||
|
|
||||||
- [x] windows
|
### 🛠️ 命令行工具
|
||||||
- [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`安装:
|
使用`go install`安装:
|
||||||
|
|
||||||
@@ -41,54 +165,40 @@ Gopeed(全称 Go Speed),是一款由`Golang`+`Flutter`开发的高速下
|
|||||||
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 liwei2633/gopeed
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 使用 Docker Compose
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 访问服务
|
|
||||||
|
|
||||||
当 docker 容器运行时,可以通过 `http://localhost:9999` 访问 web 页面。
|
|
||||||
|
|
||||||
## 赞助
|
|
||||||
|
|
||||||
如果觉得项目对你有帮助,请考虑[赞助](https://docs.gopeed.com/zh/donate)以支持这个项目的发展,非常感谢!
|
如果觉得项目对你有帮助,请考虑[赞助](https://docs.gopeed.com/zh/donate)以支持这个项目的发展,非常感谢!
|
||||||
|
|
||||||
## 界面展示
|
## 🖼️ 界面展示
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 开发
|
## 👨💻 开发
|
||||||
|
|
||||||
本项目分为前端和后端两个部分,前端使用`flutter`,后端使用`Golang`,两边通过`http`协议进行通讯,在 unix 系统下,使用的是`unix socket`,在 windows 系统下,使用的是`tcp`协议。
|
本项目分为前端和后端两个部分,前端使用`flutter`,后端使用`Golang`,两边通过`http`协议进行通讯,在 unix 系统下,使用的是`unix socket`,在 windows 系统下,使用的是`tcp`协议。
|
||||||
|
|
||||||
> 前端代码位于`ui/flutter`目录下。
|
> 前端代码位于`ui/flutter`目录下。
|
||||||
|
|
||||||
### 环境要求
|
### 🌍 环境要求
|
||||||
|
|
||||||
1. Golang 1.19+
|
1. Golang 1.23+
|
||||||
2. Flutter 3.10+
|
2. Flutter 3.24+
|
||||||
|
|
||||||
### 克隆项目
|
### 📋 克隆项目
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone [email protected]:GopeedLab/gopeed.git
|
git clone [email protected]:GopeedLab/gopeed.git
|
||||||
```
|
```
|
||||||
|
|
||||||
### 贡献代码
|
### 🤝 贡献代码
|
||||||
|
|
||||||
请参考[贡献指南](CONTRIBUTING_zh-CN.md)
|
请参考[贡献指南](CONTRIBUTING_zh-CN.md)
|
||||||
|
|
||||||
### 编译
|
### 🏗️ 编译
|
||||||
|
|
||||||
#### 桌面端
|
#### 桌面端
|
||||||
|
|
||||||
@@ -135,7 +245,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 -checklinkname=0" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -javapkg="com.gopeed" github.com/GopeedLab/gopeed/bind/mobile
|
||||||
cd ui/flutter
|
cd ui/flutter
|
||||||
flutter build apk
|
flutter build apk
|
||||||
```
|
```
|
||||||
@@ -159,10 +269,9 @@ cd ../../
|
|||||||
rm -rf cmd/web/dist
|
rm -rf cmd/web/dist
|
||||||
cp -r ui/flutter/build/web 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
|
go build -tags nosqlite,web -ldflags="-s -w" -o bin/ github.com/GopeedLab/gopeed/cmd/web
|
||||||
go run cmd/web/main.go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 感谢
|
## ❤️ 感谢
|
||||||
|
|
||||||
### 贡献者
|
### 贡献者
|
||||||
|
|
||||||
|
|||||||
+285
@@ -0,0 +1,285 @@
|
|||||||
|
# [](https://gopeed.com)
|
||||||
|
|
||||||
|
[](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)
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/7953" target="_blank"><img src="https://trendshift.io/api/badge/repositories/7953" alt="GopeedLab%2Fgopeed | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
[](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)
|
||||||
|
|
||||||
|
## 🚀 簡介
|
||||||
|
|
||||||
|
Gopeed(全稱 Go Speed),是一款使用`Golang`+`Flutter`編寫的高速下載軟體,支援(HTTP、BitTorrent、Magnet)協定,同時支援所有的平台。
|
||||||
|
|
||||||
|
前往 ✈ [主頁](https://gopeed.com/zh-CN) | 📖 [文檔](https://docs.gopeed.com/zh/)
|
||||||
|
|
||||||
|
## ⬇️ 下載
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">🪟 Windows</td>
|
||||||
|
<td><code>EXE</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>Portable</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-windows-amd64-portable.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3">🍎 MacOS</td>
|
||||||
|
<td rowspan="3"><code>DMG</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-amd64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-macos-arm64.dmg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">🐧 Linux</td>
|
||||||
|
<td><code>Flathub</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://flathub.org/apps/com.gopeed.Gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>SNAP</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://snapcraft.io/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>DEB</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.deb">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>AppImage</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-amd64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-linux-arm64.AppImage">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="4">🤖 Android</td>
|
||||||
|
<td rowspan="4"><code>APK</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>armeabi-v7a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-armeabi-v7a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64-v8a</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-arm64-v8a.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>x86_64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-android-x86_64.apk">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>📱 iOS</td>
|
||||||
|
<td><code>IPA</code></td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=Gopeed-$version-ios.ipa">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>🐳 Docker</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>universal</td>
|
||||||
|
<td><a href="https://hub.docker.com/r/liwei2633/gopeed">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2">💾 Qnap</td>
|
||||||
|
<td rowspan="2"><code>QPKG</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-amd64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-$version-qnap-arm64.qpkg">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="8">🌐 Web</td>
|
||||||
|
<td rowspan="3"><code>Windows</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-windows-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2"><code>MacOS</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-macos-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td rowspan="3"><code>Linux</code></td>
|
||||||
|
<td>amd64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-amd64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>arm64</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-arm64.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>386</td>
|
||||||
|
<td><a href="https://gopeed.com/api/download?tpl=gopeed-web-$version-linux-386.zip">📥</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
更多關於安裝的內容請參考[安裝文檔](https://docs.gopeed.com/zh/install.html)
|
||||||
|
|
||||||
|
### 🛠️ 使用 CLI 安裝
|
||||||
|
|
||||||
|
使用`go install`安裝:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install github.com/GopeedLab/gopeed/cmd/gopeed@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 💝 贊助
|
||||||
|
|
||||||
|
如果你認為該項目對你有所幫助,請考慮[贊助](https://docs.gopeed.com/zh/donate)以支持該項目的持續發展,謝謝!
|
||||||
|
|
||||||
|
## 🖼️ 軟體介面
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 👨💻 開發
|
||||||
|
|
||||||
|
該項目分為前端與後端,前端使用`flutter`編寫,後端使用`Golang`編寫,兩邊通過`http`協定進行通訊,在 unix 系統下,則使用`unix socket`,在 windows 系統下,則使用`tcp`協定。
|
||||||
|
|
||||||
|
> 前端代碼位於`ui/flutter`目錄內。
|
||||||
|
|
||||||
|
### 🌍 開發環境
|
||||||
|
|
||||||
|
1. Golang 1.23+
|
||||||
|
2. Flutter 3.24+
|
||||||
|
|
||||||
|
### 📋 克隆項目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone [email protected]:GopeedLab/gopeed.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🤝 協助開發
|
||||||
|
|
||||||
|
請參考[協助指南](CONTRIBUTING_zh-TW.md)
|
||||||
|
|
||||||
|
### 🏗️ 編譯
|
||||||
|
|
||||||
|
#### 桌面端
|
||||||
|
|
||||||
|
首先需要按照[flutter desktop 官方文檔](https://docs.flutter.dev/development/platform-integration/desktop)配置開發環境,並準備好`cgo`環境,具體方法可以自行搜索。
|
||||||
|
|
||||||
|
組建指令:
|
||||||
|
|
||||||
|
- 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
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 移動設備
|
||||||
|
|
||||||
|
需要`cgo`環境,並安裝`gomobile`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
||||||
|
go get golang.org/x/mobile/bind
|
||||||
|
gomobile init
|
||||||
|
```
|
||||||
|
|
||||||
|
組建指令:
|
||||||
|
|
||||||
|
- android
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gomobile bind -tags nosqlite -ldflags="-w -s -checklinkname=0" -o ui/flutter/android/app/libs/libgopeed.aar -target=android -androidapi 21 -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
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 網頁端
|
||||||
|
|
||||||
|
組建指令:
|
||||||
|
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
## ❤️ 感謝
|
||||||
|
|
||||||
|
### 貢獻者
|
||||||
|
|
||||||
|
<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)
|
||||||
|
|
||||||
|
## 軟體許可
|
||||||
|
|
||||||
|
該軟體遵循 [GPLv3](LICENSE) 。
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 309 KiB |
+4
-3
@@ -8,9 +8,10 @@ import (
|
|||||||
// only for local development
|
// only for local development
|
||||||
func main() {
|
func main() {
|
||||||
cfg := &model.StartConfig{
|
cfg := &model.StartConfig{
|
||||||
Network: "tcp",
|
Network: "tcp",
|
||||||
Address: "127.0.0.1:9999",
|
Address: "127.0.0.1:9999",
|
||||||
Storage: model.StorageBolt,
|
Storage: model.StorageBolt,
|
||||||
|
WebEnable: true,
|
||||||
}
|
}
|
||||||
cmd.Start(cfg)
|
cmd.Start(cfg)
|
||||||
}
|
}
|
||||||
+17
-1
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/GopeedLab/gopeed/internal/fetcher"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"github.com/GopeedLab/gopeed/pkg/download"
|
"github.com/GopeedLab/gopeed/pkg/download"
|
||||||
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
"github.com/GopeedLab/gopeed/pkg/protocol/http"
|
||||||
@@ -47,16 +48,31 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
printProgress(emptyTask, "downloading...")
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lastLineLen = 0
|
lastLineLen = 0
|
||||||
sb = new(strings.Builder)
|
sb = new(strings.Builder)
|
||||||
|
emptyTask = &download.Task{
|
||||||
|
Progress: &download.Progress{},
|
||||||
|
Meta: &fetcher.FetcherMeta{
|
||||||
|
Res: &base.Resource{},
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func printProgress(task *download.Task, title string) {
|
func printProgress(task *download.Task, title string) {
|
||||||
rate := float64(task.Progress.Downloaded) / float64(task.Meta.Res.Size)
|
var rate float64
|
||||||
|
if task.Meta.Res == nil {
|
||||||
|
task = emptyTask
|
||||||
|
}
|
||||||
|
if task.Meta.Res.Size <= 0 {
|
||||||
|
rate = 0
|
||||||
|
} else {
|
||||||
|
rate = float64(task.Progress.Downloaded) / float64(task.Meta.Res.Size)
|
||||||
|
}
|
||||||
completeWidth := int(progressWidth * rate)
|
completeWidth := int(progressWidth * rate)
|
||||||
speed := util.ByteFmt(task.Progress.Speed)
|
speed := util.ByteFmt(task.Progress.Speed)
|
||||||
totalSize := util.ByteFmt(task.Meta.Res.Size)
|
totalSize := util.ByteFmt(task.Meta.Res.Size)
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/browser"
|
||||||
|
"github.com/shirou/gopsutil/v4/process"
|
||||||
|
)
|
||||||
|
|
||||||
|
const identifier = "gopeed"
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Params json.RawMessage `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Data any `json:"data,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var apiMap = map[string]func(params json.RawMessage) (data any, err error){
|
||||||
|
"ping": func(params json.RawMessage) (data any, err error) {
|
||||||
|
processes, err := process.Processes()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range processes {
|
||||||
|
name, err := p.Name()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(strings.ToLower(name), strings.ToLower(identifier)) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
"create": func(params json.RawMessage) (data any, err error) {
|
||||||
|
var strParams string
|
||||||
|
if err = json.Unmarshal(params, &strParams); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = browser.OpenURL(fmt.Sprintf("%s:///create?params=%s", identifier, strParams))
|
||||||
|
return
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// go build -ldflags="-s -w" -o ui/flutter/assets/exec/ github.com/GopeedLab/gopeed/cmd/host
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
for {
|
||||||
|
// Read message length (first 4 bytes)
|
||||||
|
var length uint32
|
||||||
|
if err := binary.Read(os.Stdin, binary.NativeEndian, &length); err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
// Connection closed by Chrome
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sendError("Failed to read message length: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the message
|
||||||
|
input := make([]byte, length)
|
||||||
|
if _, err := io.ReadFull(os.Stdin, input); err != nil {
|
||||||
|
sendError("Failed to read message: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse message
|
||||||
|
var message Message
|
||||||
|
if err := json.Unmarshal(input, &message); err != nil {
|
||||||
|
sendError("Failed to parse message: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle request
|
||||||
|
var data any
|
||||||
|
var err error
|
||||||
|
if handler, ok := apiMap[message.Method]; ok {
|
||||||
|
data, err = handler(message.Params)
|
||||||
|
} else {
|
||||||
|
err = errors.New("Unknown method: " + message.Method)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
sendError(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sendResponse(0, data, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendResponse(code int, data interface{}, message string) {
|
||||||
|
response := Response{
|
||||||
|
Code: code,
|
||||||
|
Data: data,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode response
|
||||||
|
responseBytes, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
sendError("Failed to encode response: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write message length
|
||||||
|
binary.Write(os.Stdout, binary.NativeEndian, uint32(len(responseBytes)))
|
||||||
|
// Write message
|
||||||
|
os.Stdout.Write(responseBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendError(msg string) {
|
||||||
|
sendResponse(1, nil, msg)
|
||||||
|
}
|
||||||
+38
-6
@@ -3,11 +3,14 @@ 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"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed banner.txt
|
//go:embed banner.txt
|
||||||
@@ -24,17 +27,46 @@ 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 config
|
||||||
userDir, err := os.UserHomeDir()
|
if cfg.DownloadConfig != nil {
|
||||||
if err == nil {
|
cfg.DownloadConfig.Merge(downloadCfg)
|
||||||
downloadDir := filepath.Join(userDir, "Downloads")
|
// TODO Use PatchConfig
|
||||||
downloadCfg.DownloadDir = downloadDir
|
rest.Downloader.PutConfig(cfg.DownloadConfig)
|
||||||
rest.Downloader.PutConfig(downloadCfg)
|
downloadCfg = cfg.DownloadConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadDir := downloadCfg.DownloadDir
|
||||||
|
// Set default download dir, in docker, it will be ${exe}/Downloads, else it will be ${user}/Downloads
|
||||||
|
if downloadDir == "" {
|
||||||
|
if base.InDocker == "true" {
|
||||||
|
downloadDir = filepath.Join(filepath.Dir(cfg.StorageDir), "Downloads")
|
||||||
|
} else {
|
||||||
|
userDir, err := os.UserHomeDir()
|
||||||
|
if err == nil {
|
||||||
|
downloadDir = filepath.Join(userDir, "Downloads")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if downloadDir != "" {
|
||||||
|
downloadCfg.DownloadDir = downloadDir
|
||||||
|
rest.Downloader.PutConfig(downloadCfg)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
watchExit()
|
||||||
|
|
||||||
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 {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func watchExit() {
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
sig := <-sigs
|
||||||
|
fmt.Printf("Server is shutting down due to signal: %s\n", sig)
|
||||||
|
rest.Downloader.Close()
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/browser"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// go build -ldflags="-s -w" -o ui/flutter/assets/exec/ github.com/GopeedLab/gopeed/cmd/updater
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
pid := flag.Int("pid", 0, "PID of the process to update")
|
||||||
|
updateChannel := flag.String("channel", "", "Update channel")
|
||||||
|
packagePath := flag.String("asset", "", "Path to the package asset")
|
||||||
|
logPath := flag.String("log", "", "Log file path")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *pid == 0 {
|
||||||
|
log.Println("Invalid PID")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if *updateChannel == "" {
|
||||||
|
log.Println("Invalid update channel")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *logPath != "" {
|
||||||
|
logFile, err := os.OpenFile(*logPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
|
||||||
|
if err == nil {
|
||||||
|
defer logFile.Close()
|
||||||
|
log.SetOutput(logFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
restart bool
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if restart, err = update(*pid, *updateChannel, *packagePath); err != nil {
|
||||||
|
log.Printf("Update failed: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart the application
|
||||||
|
if restart {
|
||||||
|
browser.OpenURL("gopeed:///")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete package asset
|
||||||
|
if *packagePath != "" {
|
||||||
|
os.Remove(*packagePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(pid int, updateChannel, packagePath string) (restart bool, err error) {
|
||||||
|
killSignalChan := make(chan any, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-killSignalChan
|
||||||
|
|
||||||
|
if err = killProcess(pid); err != nil {
|
||||||
|
log.Printf("Failed to kill process: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = waitForProcessExit(pid); err != nil {
|
||||||
|
log.Printf("Failed to wait for process exit: %v\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
appDir := filepath.Dir(os.Args[0])
|
||||||
|
log.Printf("Updating process updateChannel=%s packagePath=%s appDir=%s\n", updateChannel, packagePath, appDir)
|
||||||
|
if restart, err = install(killSignalChan, updateChannel, packagePath, appDir); err != nil {
|
||||||
|
return false, errors.Wrap(err, "failed to install package")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForProcessExit(pid int) error {
|
||||||
|
deadline := time.Now().Add(10 * time.Second)
|
||||||
|
for time.Now().Before(deadline) {
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
// On some systems, error is returned if process doesn't exist
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send null signal to test if process exists
|
||||||
|
err = process.Signal(syscall.Signal(0))
|
||||||
|
if err != nil {
|
||||||
|
// If error occurs, the process no longer exists
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("process %d still running after timeout", pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func killProcess(pid int) error {
|
||||||
|
process, err := os.FindProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.Kill()
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
//go:build darwin
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func install(killSignalChan chan<- any, updateChannel, packagePath, destDir string) (bool, error) {
|
||||||
|
return true, installByDmg(killSignalChan, packagePath, destDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// installByDmg handles macOS dmg package installation
|
||||||
|
func installByDmg(killSignalChan chan<- any, packagePath, destDir string) error {
|
||||||
|
// /Applications/Gopeed.app/Contents/MacOS -> /Applications
|
||||||
|
appPath := getParentDir(getParentDir(getParentDir(destDir)))
|
||||||
|
output, err := exec.Command("hdiutil", "attach", packagePath, "-nobrowse").Output()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mountPoint := ""
|
||||||
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
|
if strings.Contains(line, "/Volumes/") {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) > 2 {
|
||||||
|
mountPoint = fields[len(fields)-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mountPoint == "" {
|
||||||
|
return fmt.Errorf("failed to get mount point")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach the mounted DMG
|
||||||
|
defer exec.Command("hdiutil", "detach", mountPoint, "-quiet").Run()
|
||||||
|
|
||||||
|
matches, err := filepath.Glob(filepath.Join(mountPoint, "*.app"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return fmt.Errorf("no .app found in dmg")
|
||||||
|
}
|
||||||
|
|
||||||
|
killSignalChan <- nil
|
||||||
|
|
||||||
|
// Copy the new app to the destination
|
||||||
|
// cp -Rf /Volumes/GoPeed/GoPeed.app /Applications
|
||||||
|
if err := exec.Command("cp", "-Rf", matches[0], appPath).Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get parent directory safely, handling trailing separators
|
||||||
|
func getParentDir(path string) string {
|
||||||
|
// Remove trailing separators if they exist
|
||||||
|
path = strings.TrimRight(path, string(filepath.Separator))
|
||||||
|
// Now get the parent directory
|
||||||
|
return filepath.Dir(path)
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func install(killSignalChan chan<- any, updateChannel, packagePath, destDir string) (bool, error) {
|
||||||
|
killSignalChan <- nil
|
||||||
|
switch updateChannel {
|
||||||
|
case "linuxDeb":
|
||||||
|
return true, installByDeb(packagePath)
|
||||||
|
case "linuxFlathub":
|
||||||
|
return true, installByFlathub()
|
||||||
|
case "linuxSnap":
|
||||||
|
return true, installBySnap()
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf("unsupported update channel for Linux: %s", updateChannel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeInTerminal tries to execute a command in one of several common terminal emulators
|
||||||
|
func executeInTerminal(command string) error {
|
||||||
|
terminals := []string{
|
||||||
|
"gnome-terminal", // GNOME
|
||||||
|
"konsole", // KDE
|
||||||
|
"xfce4-terminal", // XFCE
|
||||||
|
"xterm", // X11
|
||||||
|
}
|
||||||
|
|
||||||
|
command = fmt.Sprintf(`echo "Starting update..." && echo "[CMD] %s" && %s`, command, command)
|
||||||
|
|
||||||
|
for _, term := range terminals {
|
||||||
|
if _, err := exec.LookPath(term); err == nil {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
switch term {
|
||||||
|
case "gnome-terminal", "xfce4-terminal":
|
||||||
|
cmd = exec.Command(term, "--", "bash", "-c", command)
|
||||||
|
case "konsole":
|
||||||
|
cmd = exec.Command(term, "-e", "bash", "-c", command)
|
||||||
|
case "xterm":
|
||||||
|
cmd = exec.Command(term, "-e", command)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("no suitable terminal emulator found. Please install gnome-terminal, konsole, xfce4-terminal or xterm")
|
||||||
|
}
|
||||||
|
|
||||||
|
// installByDeb installs the .deb package
|
||||||
|
func installByDeb(packagePath string) error {
|
||||||
|
command := fmt.Sprintf(`sudo dpkg -i "%s"`, packagePath)
|
||||||
|
return executeInTerminal(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// installByFlathub updates the application via Flathub
|
||||||
|
func installByFlathub() error {
|
||||||
|
command := "flatpak update com.gopeed.Gopeed -y"
|
||||||
|
return executeInTerminal(command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// installBySnap updates the application via Snap
|
||||||
|
func installBySnap() error {
|
||||||
|
command := "sudo snap refresh gopeed"
|
||||||
|
return executeInTerminal(command)
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func install(killSignalChan chan<- any, updateChannel, packagePath, destDir string) (bool, error) {
|
||||||
|
switch updateChannel {
|
||||||
|
case "windowsInstaller":
|
||||||
|
return false, installByInstaller(killSignalChan, packagePath, destDir)
|
||||||
|
default:
|
||||||
|
return true, installByPortable(killSignalChan, packagePath, destDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// installByInstaller extracts the installer from the zip file and runs it
|
||||||
|
func installByInstaller(killSignalChan chan<- any, packagePath, destDir string) error {
|
||||||
|
// Create a temp directory for extraction
|
||||||
|
tempDir, err := os.MkdirTemp("", "gopeed_update")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tempDir)
|
||||||
|
|
||||||
|
// Extract the zip file
|
||||||
|
reader, err := zip.OpenReader(packagePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
// Find the installer file
|
||||||
|
var installerPath string
|
||||||
|
for _, file := range reader.File {
|
||||||
|
if file.FileInfo().IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract file
|
||||||
|
path := filepath.Join(tempDir, file.Name)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dstFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFile, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
dstFile.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(dstFile, srcFile)
|
||||||
|
srcFile.Close()
|
||||||
|
dstFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is likely an installer (.exe, .msi), save its path
|
||||||
|
ext := strings.ToLower(filepath.Ext(file.Name))
|
||||||
|
if ext == ".exe" || ext == ".msi" {
|
||||||
|
installerPath = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if installerPath == "" {
|
||||||
|
return fmt.Errorf("no installer found in the update package")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the installer
|
||||||
|
cmd := exec.Command(installerPath)
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
killSignalChan <- nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// installByPortable extracts the portable version to the destination directory
|
||||||
|
func installByPortable(killSignalChan chan<- any, packagePath, destDir string) error {
|
||||||
|
killSignalChan <- nil
|
||||||
|
|
||||||
|
reader, err := zip.OpenReader(packagePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
for _, file := range reader.File {
|
||||||
|
path := filepath.Join(destDir, file.Name)
|
||||||
|
|
||||||
|
if file.FileInfo().IsDir() {
|
||||||
|
os.MkdirAll(path, file.Mode())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dstFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFile, err := file.Open()
|
||||||
|
if err != nil {
|
||||||
|
dstFile.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(dstFile, srcFile)
|
||||||
|
srcFile.Close()
|
||||||
|
dstFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+171
-47
@@ -3,73 +3,197 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
Address *string `json:"address"`
|
Address *string `json:"address"`
|
||||||
Port *int `json:"port"`
|
Port *int `json:"port"`
|
||||||
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"`
|
||||||
|
WhiteDownloadDirs []string `json:"whiteDownloadDirs"`
|
||||||
|
// DownloadConfig when the first time to start the server, it will be configured as initial value
|
||||||
|
DownloadConfig *base.DownloaderStoreConfig `json:"downloadConfig"`
|
||||||
|
|
||||||
configPath *string
|
configPath *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse() *args {
|
func parse() *args {
|
||||||
var cliArgs args
|
cfg := &args{}
|
||||||
cliArgs.Address = flag.String("A", "0.0.0.0", "Bind Address")
|
|
||||||
cliArgs.Port = flag.Int("P", 9999, "Bind Port")
|
cliConfig := loadCliArgs()
|
||||||
cliArgs.Username = flag.String("u", "gopeed", "HTTP Basic Auth Username")
|
loadConfigFile(cfg, *cliConfig.configPath)
|
||||||
cliArgs.Password = flag.String("p", "", "HTTP Basic Auth Password")
|
loadEnvVars(cfg)
|
||||||
cliArgs.ApiToken = flag.String("T", "", "API token, that can only be used when basic authentication is enabled.")
|
// override with non-default command line arguments
|
||||||
cliArgs.configPath = flag.String("c", "./config.json", "Config file path")
|
overrideWithCliArgs(cfg, cliConfig)
|
||||||
|
// set default values
|
||||||
|
setDefaults(cfg, cliConfig)
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadCliArgs parses command line arguments and returns initial config
|
||||||
|
func loadCliArgs() *args {
|
||||||
|
cfg := &args{}
|
||||||
|
cfg.Address = flag.String("A", "0.0.0.0", "Bind Address")
|
||||||
|
cfg.Port = flag.Int("P", 9999, "Bind Port")
|
||||||
|
cfg.Username = flag.String("u", "gopeed", "Web Authentication Username")
|
||||||
|
cfg.Password = flag.String("p", "", "Web Authentication Password, if no password is set, web authentication will not be enabled")
|
||||||
|
cfg.ApiToken = flag.String("T", "", "API token, it must be configured when using HTTP API in the case of enabling web authentication")
|
||||||
|
cfg.StorageDir = flag.String("d", "", "Storage directory")
|
||||||
|
whiteDownloadDirs := flag.String("w", "", "White download directories, comma-separated")
|
||||||
|
cfg.configPath = flag.String("c", "./config.json", "Config file path")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// args priority: config file > cli args
|
// Parse white download directories from comma-separated string
|
||||||
cfgArgs := loadConfig(*cliArgs.configPath)
|
if whiteDownloadDirs != nil && *whiteDownloadDirs != "" {
|
||||||
if cfgArgs.Address == nil {
|
dirs := strings.Split(*whiteDownloadDirs, ",")
|
||||||
cfgArgs.Address = cliArgs.Address
|
for i := range dirs {
|
||||||
|
dirs[i] = strings.TrimSpace(dirs[i])
|
||||||
|
}
|
||||||
|
cfg.WhiteDownloadDirs = dirs
|
||||||
}
|
}
|
||||||
if cfgArgs.Port == nil {
|
|
||||||
cfgArgs.Port = cliArgs.Port
|
return cfg
|
||||||
}
|
|
||||||
if cfgArgs.Username == nil {
|
|
||||||
cfgArgs.Username = cliArgs.Username
|
|
||||||
}
|
|
||||||
if cfgArgs.Password == nil {
|
|
||||||
cfgArgs.Password = cliArgs.Password
|
|
||||||
}
|
|
||||||
if cfgArgs.ApiToken == nil {
|
|
||||||
cfgArgs.ApiToken = cliArgs.ApiToken
|
|
||||||
}
|
|
||||||
return cfgArgs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig(path string) *args {
|
// overrideWithCliArgs overrides config with non-empty command line arguments
|
||||||
var args args
|
func overrideWithCliArgs(cfg *args, cliConfig *args) {
|
||||||
|
flag.Visit(func(f *flag.Flag) {
|
||||||
if !filepath.IsAbs(path) {
|
switch f.Name {
|
||||||
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
|
case "A":
|
||||||
if err != nil {
|
cfg.Address = cliConfig.Address
|
||||||
return &args
|
case "P":
|
||||||
|
cfg.Port = cliConfig.Port
|
||||||
|
case "u":
|
||||||
|
cfg.Username = cliConfig.Username
|
||||||
|
case "p":
|
||||||
|
cfg.Password = cliConfig.Password
|
||||||
|
case "T":
|
||||||
|
cfg.ApiToken = cliConfig.ApiToken
|
||||||
|
case "d":
|
||||||
|
cfg.StorageDir = cliConfig.StorageDir
|
||||||
|
case "w":
|
||||||
|
cfg.WhiteDownloadDirs = cliConfig.WhiteDownloadDirs
|
||||||
|
case "c":
|
||||||
|
cfg.configPath = cliConfig.configPath
|
||||||
}
|
}
|
||||||
path = filepath.Join(dir, path)
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// setDefaults sets default values for any unset configuration fields
|
||||||
|
func setDefaults(cfg *args, cliConfig *args) {
|
||||||
|
if cfg.Address == nil {
|
||||||
|
cfg.Address = cliConfig.Address
|
||||||
}
|
}
|
||||||
file, err := os.ReadFile(path)
|
if cfg.Port == nil {
|
||||||
|
cfg.Port = cliConfig.Port
|
||||||
|
}
|
||||||
|
if cfg.Username == nil {
|
||||||
|
cfg.Username = cliConfig.Username
|
||||||
|
}
|
||||||
|
if cfg.Password == nil {
|
||||||
|
cfg.Password = cliConfig.Password
|
||||||
|
}
|
||||||
|
if cfg.ApiToken == nil {
|
||||||
|
cfg.ApiToken = cliConfig.ApiToken
|
||||||
|
}
|
||||||
|
if cfg.StorageDir == nil {
|
||||||
|
cfg.StorageDir = cliConfig.StorageDir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadConfigFile loads configuration from file
|
||||||
|
func loadConfigFile(cfg *args, configPath string) {
|
||||||
|
if !filepath.IsAbs(configPath) {
|
||||||
|
dir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
configPath = filepath.Join(dir, configPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.ReadFile(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return &args
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("config file read failed, reason:" + err.Error())
|
return
|
||||||
return &args
|
|
||||||
}
|
}
|
||||||
if err = json.Unmarshal(file, &args); err != nil {
|
|
||||||
fmt.Println("config file parse failed, reason:" + err.Error())
|
if err = json.Unmarshal(file, cfg); err != nil {
|
||||||
return &args
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadEnvVars loads configuration from environment variables with prefix GOPEED_
|
||||||
|
func loadEnvVars(cfg *args) {
|
||||||
|
v := reflect.ValueOf(cfg).Elem()
|
||||||
|
t := reflect.TypeOf(cfg).Elem()
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
field := v.Field(i)
|
||||||
|
fieldType := t.Field(i)
|
||||||
|
|
||||||
|
// Get json tag as environment variable suffix
|
||||||
|
jsonTag := fieldType.Tag.Get("json")
|
||||||
|
if jsonTag == "" || jsonTag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove options like omitempty
|
||||||
|
if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 {
|
||||||
|
jsonTag = jsonTag[:commaIdx]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to uppercase and add GOPEED_ prefix
|
||||||
|
envKey := "GOPEED_" + strings.ToUpper(jsonTag)
|
||||||
|
envValue := os.Getenv(envKey)
|
||||||
|
|
||||||
|
if envValue == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set value based on field type
|
||||||
|
if field.Kind() == reflect.Ptr {
|
||||||
|
if field.IsNil() {
|
||||||
|
// Create new pointer instance
|
||||||
|
newVal := reflect.New(field.Type().Elem())
|
||||||
|
field.Set(newVal)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch field.Type().Elem().Kind() {
|
||||||
|
case reflect.String:
|
||||||
|
field.Elem().SetString(envValue)
|
||||||
|
case reflect.Int:
|
||||||
|
if intVal, err := strconv.Atoi(envValue); err == nil {
|
||||||
|
field.Elem().SetInt(int64(intVal))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// For complex types like DownloadConfig, try JSON unmarshaling
|
||||||
|
if field.Type().Elem() == reflect.TypeOf(base.DownloaderStoreConfig{}) {
|
||||||
|
var config base.DownloaderStoreConfig
|
||||||
|
if err := json.Unmarshal([]byte(envValue), &config); err == nil {
|
||||||
|
field.Set(reflect.ValueOf(&config))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if field.Kind() == reflect.Slice {
|
||||||
|
// Handle non-pointer slice types (like []string for WhiteDownloadDirs)
|
||||||
|
if field.Type().Elem().Kind() == reflect.String {
|
||||||
|
dirs := strings.Split(envValue, ",")
|
||||||
|
for i := range dirs {
|
||||||
|
dirs[i] = strings.TrimSpace(dirs[i])
|
||||||
|
}
|
||||||
|
field.Set(reflect.ValueOf(dirs))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("config file loaded: %s\n", path)
|
|
||||||
return &args
|
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large.
Load diff
+28
-11
@@ -6,9 +6,12 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/GopeedLab/gopeed/cmd"
|
"github.com/GopeedLab/gopeed/cmd"
|
||||||
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
"github.com/GopeedLab/gopeed/pkg/rest/model"
|
||||||
"io/fs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed dist/*
|
//go:embed dist/*
|
||||||
@@ -21,23 +24,37 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
args := parse()
|
args := parse()
|
||||||
var webBasicAuth *model.WebBasicAuth
|
var webAuth *model.WebAuth
|
||||||
if isNotBlank(args.Username) && isNotBlank(args.Password) {
|
if isNotBlank(args.Username) && isNotBlank(args.Password) {
|
||||||
webBasicAuth = &model.WebBasicAuth{
|
webAuth = &model.WebAuth{
|
||||||
Username: *args.Username,
|
Username: *args.Username,
|
||||||
Password: *args.Password,
|
Password: *args.Password,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var storageDir string
|
||||||
|
if args.StorageDir != nil && *args.StorageDir != "" {
|
||||||
|
storageDir = *args.StorageDir
|
||||||
|
} else {
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
storageDir = filepath.Join(filepath.Dir(exe), "storage")
|
||||||
|
}
|
||||||
|
|
||||||
cfg := &model.StartConfig{
|
cfg := &model.StartConfig{
|
||||||
Network: "tcp",
|
Network: "tcp",
|
||||||
Address: fmt.Sprintf("%s:%d", *args.Address, *args.Port),
|
Address: fmt.Sprintf("%s:%d", *args.Address, *args.Port),
|
||||||
Storage: model.StorageBolt,
|
Storage: model.StorageBolt,
|
||||||
ApiToken: *args.ApiToken,
|
StorageDir: storageDir,
|
||||||
ProductionMode: true,
|
WhiteDownloadDirs: args.WhiteDownloadDirs,
|
||||||
WebEnable: true,
|
ApiToken: *args.ApiToken,
|
||||||
WebFS: sub,
|
DownloadConfig: args.DownloadConfig,
|
||||||
WebBasicAuth: webBasicAuth,
|
ProductionMode: true,
|
||||||
|
WebEnable: true,
|
||||||
|
WebFS: sub,
|
||||||
|
WebAuth: webAuth,
|
||||||
}
|
}
|
||||||
cmd.Start(cfg)
|
cmd.Start(cfg)
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-10
@@ -1,11 +1,15 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
gopeed:
|
gopeed:
|
||||||
container_name: gopeed
|
container_name: gopeed
|
||||||
ports:
|
ports:
|
||||||
- 9999:9999 # HTTP port (host:container)
|
- 9999:9999 # HTTP port (host:container)
|
||||||
image: liwei2633/gopeed
|
environment:
|
||||||
volumes:
|
- PUID=0
|
||||||
- ~/Downloads:/root/Downloads # replace with your prefer path
|
- PGID=0
|
||||||
restart: unless-stopped
|
- UMASK=022
|
||||||
|
volumes:
|
||||||
|
- ~/gopeed/Downloads:/app/Downloads # mount download path
|
||||||
|
#- ~/gopeed/storage:/app/storage # if you need to mount storage path, uncomment this line
|
||||||
|
restart: unless-stopped
|
||||||
|
image: liwei2633/gopeed
|
||||||
|
# command: -u Username -p Password # optional authentication
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
chown -R ${PUID}:${PGID} /app
|
||||||
|
|
||||||
|
umask ${UMASK}
|
||||||
|
|
||||||
|
exec su-exec ${PUID}:${PGID} ./gopeed "$@"
|
||||||
@@ -1,107 +1,152 @@
|
|||||||
module github.com/GopeedLab/gopeed
|
module github.com/GopeedLab/gopeed
|
||||||
|
|
||||||
go 1.19
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.23.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/anacrolix/missinggo/v2 v2.7.2-0.20230527121029-a582b4f397b9
|
github.com/anacrolix/missinggo/v2 v2.8.0
|
||||||
github.com/anacrolix/torrent v1.52.5
|
github.com/anacrolix/torrent v1.57.2-0.20241017235801-4d8437a05621
|
||||||
github.com/dop251/goja v0.0.0-20230828202809-3dbe69dd2b8e
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20230821135201-94e508132562
|
github.com/dop251/goja v0.0.0-20240919115326-6c7d1df7ff05
|
||||||
|
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc
|
||||||
github.com/go-git/go-git/v5 v5.8.1
|
github.com/go-git/go-git/v5 v5.8.1
|
||||||
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/imroc/req/v3 v3.52.2
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0
|
github.com/matoous/go-nanoid/v2 v2.0.0
|
||||||
github.com/virtuald/go-paniclog v0.0.0-20190812204905-43a7fa316459
|
github.com/mattn/go-ieproxy v0.0.12
|
||||||
go.etcd.io/bbolt v1.3.7-0.20231005155708-db45d0d6b1f6
|
github.com/pkg/errors v0.9.1
|
||||||
golang.org/x/sync v0.3.0
|
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529
|
||||||
|
github.com/rs/zerolog v1.31.0
|
||||||
|
github.com/xiaoqidun/setft v0.0.0-20220310121541-be86327699ad
|
||||||
|
go.etcd.io/bbolt v1.3.11
|
||||||
|
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
|
||||||
|
golang.org/x/sync v0.13.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
|
github.com/ebitengine/purego v0.8.1 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
|
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
|
github.com/icholy/digest v1.1.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
|
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
|
||||||
|
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
|
||||||
|
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
|
||||||
|
github.com/quic-go/qpack v0.5.1 // indirect
|
||||||
|
github.com/quic-go/quic-go v0.51.0 // indirect
|
||||||
|
github.com/refraction-networking/utls v1.6.7 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
|
go.uber.org/mock v0.5.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
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.9.4 // 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.6.0 // indirect
|
||||||
github.com/anacrolix/dht/v2 v2.19.2-0.20221121215055-066ad8494444 // indirect
|
github.com/anacrolix/dht/v2 v2.22.0 // indirect
|
||||||
github.com/anacrolix/envpprof v1.2.1 // indirect
|
github.com/anacrolix/envpprof v1.4.0 // indirect
|
||||||
github.com/anacrolix/generics v0.0.0-20230428105757-683593396d68 // indirect
|
github.com/anacrolix/generics v0.0.3-0.20240902042256-7fb2702ef0ca // 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.16.0 // 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.1.1 // indirect
|
||||||
github.com/anacrolix/multiless v0.3.0 // indirect
|
github.com/anacrolix/multiless v0.4.0 // 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.3 // indirect
|
||||||
github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect
|
github.com/anacrolix/upnp v0.1.4 // 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.15.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/cespare/xxhash v1.1.0 // indirect
|
||||||
|
github.com/cloudflare/circl v1.6.1 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
github.com/dlclark/regexp2 v1.11.4 // 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.2.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.5 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.2 // 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.4+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.3 // indirect
|
||||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
|
github.com/google/pprof v0.0.0-20250423184734-337e5dd93bb4 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.3 // indirect
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/huandu/xstrings v1.5.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/klauspost/cpuid/v2 v2.2.9 // 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-isatty v0.0.20 // indirect
|
||||||
|
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||||
|
github.com/mr-tron/base58 v1.2.0 // 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/multiformats/go-multihash v0.2.3 // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.4 // indirect
|
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||||
github.com/pion/ice/v2 v2.2.6 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/pion/interceptor v0.1.11 // indirect
|
github.com/pion/datachannel v1.5.9 // indirect
|
||||||
|
github.com/pion/dtls/v3 v3.0.4 // indirect
|
||||||
|
github.com/pion/ice/v4 v4.0.2 // indirect
|
||||||
|
github.com/pion/interceptor v0.1.37 // indirect
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
github.com/pion/mdns v0.0.5 // indirect
|
github.com/pion/mdns/v2 v2.0.7 // 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.14 // indirect
|
||||||
github.com/pion/rtp v1.7.13 // indirect
|
github.com/pion/rtp v1.8.9 // indirect
|
||||||
github.com/pion/sctp v1.8.2 // indirect
|
github.com/pion/sctp v1.8.33 // indirect
|
||||||
github.com/pion/sdp/v3 v3.0.5 // indirect
|
github.com/pion/sdp/v3 v3.0.9 // indirect
|
||||||
github.com/pion/srtp/v2 v2.0.9 // indirect
|
github.com/pion/srtp/v3 v3.0.4 // indirect
|
||||||
github.com/pion/stun v0.3.5 // indirect
|
github.com/pion/stun/v3 v3.0.0 // indirect
|
||||||
github.com/pion/transport v0.13.1 // indirect
|
github.com/pion/transport/v3 v3.0.7 // indirect
|
||||||
github.com/pion/transport/v2 v2.0.0 // indirect
|
github.com/pion/turn/v4 v4.0.0 // indirect
|
||||||
github.com/pion/turn/v2 v2.0.8 // indirect
|
github.com/pion/webrtc/v4 v4.0.2 // 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/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
|
||||||
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect
|
github.com/protolambda/ctxlock v0.1.0 // indirect
|
||||||
github.com/rs/zerolog v1.31.0 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/sergi/go-diff v1.1.0 // indirect
|
github.com/sergi/go-diff v1.1.0 // indirect
|
||||||
|
github.com/shirou/gopsutil/v4 v4.24.12
|
||||||
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/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
|
github.com/tidwall/btree v1.7.0 // indirect
|
||||||
|
github.com/wlynxg/anet v0.0.5 // 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
|
go.opentelemetry.io/otel v1.32.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.8.0 // indirect
|
go.opentelemetry.io/otel/metric v1.32.0 // indirect
|
||||||
golang.org/x/crypto v0.11.0 // indirect
|
go.opentelemetry.io/otel/trace v1.32.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220613132600-b0d781184e0d // indirect
|
golang.org/x/crypto v0.37.0 // indirect
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
golang.org/x/mod v0.24.0 // indirect
|
||||||
golang.org/x/net v0.12.0 // indirect
|
golang.org/x/net v0.39.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
golang.org/x/text v0.11.0 // indirect
|
golang.org/x/text v0.24.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
golang.org/x/time v0.8.0 // indirect
|
||||||
golang.org/x/tools v0.6.0 // indirect
|
golang.org/x/tools v0.32.0 // indirect
|
||||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
lukechampine.com/blake3 v1.3.0 // indirect
|
||||||
|
modernc.org/libc v1.61.0 // indirect
|
||||||
|
modernc.org/mathutil v1.6.0 // indirect
|
||||||
|
modernc.org/memory v1.8.0 // indirect
|
||||||
|
modernc.org/sqlite v1.33.1 // indirect
|
||||||
|
zombiezen.com/go/sqlite v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
GetConfig func(v any) (bool, error)
|
GetConfig func(v any)
|
||||||
|
GetProxy func(requestProxy *base.RequestProxy) func(*http.Request) (*url.URL, error)
|
||||||
FileController
|
FileController
|
||||||
//ContextDialer() (proxy.Dialer, error)
|
//ContextDialer() (proxy.Dialer, error)
|
||||||
}
|
}
|
||||||
@@ -20,10 +24,11 @@ type DefaultFileController struct {
|
|||||||
|
|
||||||
func NewController() *Controller {
|
func NewController() *Controller {
|
||||||
return &Controller{
|
return &Controller{
|
||||||
FileController: &DefaultFileController{},
|
GetConfig: func(v any) {},
|
||||||
GetConfig: func(v any) (bool, error) {
|
GetProxy: func(requestProxy *base.RequestProxy) func(*http.Request) (*url.URL, error) {
|
||||||
return false, nil
|
return requestProxy.ToHandler()
|
||||||
},
|
},
|
||||||
|
FileController: &DefaultFileController{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ import (
|
|||||||
"github.com/GopeedLab/gopeed/internal/controller"
|
"github.com/GopeedLab/gopeed/internal/controller"
|
||||||
"github.com/GopeedLab/gopeed/pkg/base"
|
"github.com/GopeedLab/gopeed/pkg/base"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Fetcher defines the interface for a download protocol.
|
// Fetcher defines the interface for a download protocol.
|
||||||
// One fetcher for each download task
|
// Each download task will have a corresponding Fetcher instance for the management of the download task
|
||||||
type Fetcher interface {
|
type Fetcher interface {
|
||||||
// Name return the name of the protocol.
|
|
||||||
Name() string
|
|
||||||
|
|
||||||
Setup(ctl *controller.Controller)
|
Setup(ctl *controller.Controller)
|
||||||
// Resolve resource info from request
|
// Resolve resource info from request
|
||||||
Resolve(req *base.Request) error
|
Resolve(req *base.Request) error
|
||||||
@@ -21,6 +19,8 @@ type Fetcher interface {
|
|||||||
Pause() error
|
Pause() error
|
||||||
Close() error
|
Close() error
|
||||||
|
|
||||||
|
// Stats refreshes health statistics and returns the latest information
|
||||||
|
Stats() any
|
||||||
// Meta returns the meta information of the download.
|
// Meta returns the meta information of the download.
|
||||||
Meta() *FetcherMeta
|
Meta() *FetcherMeta
|
||||||
// Progress returns the progress of the download.
|
// Progress returns the progress of the download.
|
||||||
@@ -29,6 +29,12 @@ type Fetcher interface {
|
|||||||
Wait() error
|
Wait() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Uploader interface {
|
||||||
|
Upload() error
|
||||||
|
UploadedBytes() int64
|
||||||
|
WaitUpload() error
|
||||||
|
}
|
||||||
|
|
||||||
// FetcherMeta defines the meta information of a fetcher.
|
// FetcherMeta defines the meta information of a fetcher.
|
||||||
type FetcherMeta struct {
|
type FetcherMeta struct {
|
||||||
Req *base.Request `json:"req"`
|
Req *base.Request `json:"req"`
|
||||||
@@ -57,17 +63,66 @@ func (m *FetcherMeta) SingleFilepath() string {
|
|||||||
return path.Join(m.Opts.Path, file.Path, fileName)
|
return path.Join(m.Opts.Path, file.Path, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FetcherBuilder defines the interface for a fetcher builder.
|
// RootDirPath return the root dir path of the task file.
|
||||||
type FetcherBuilder interface {
|
func (m *FetcherMeta) RootDirPath() string {
|
||||||
// Schemes returns the schemes supported by the fetcher.
|
if m.Res.Name != "" {
|
||||||
Schemes() []string
|
return m.FolderPath()
|
||||||
|
} else {
|
||||||
|
return m.Opts.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type FilterType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FilterTypeUrl url type, pattern is the scheme, e.g. http://github.com -> http
|
||||||
|
FilterTypeUrl FilterType = iota
|
||||||
|
// FilterTypeFile file type, pattern is the file extension name, e.g. test.torrent -> torrent
|
||||||
|
FilterTypeFile
|
||||||
|
// FilterTypeBase64 base64 data type, pattern is the data mime type, e.g. data:application/x-bittorrent;base64 -> application/x-bittorrent
|
||||||
|
FilterTypeBase64
|
||||||
|
)
|
||||||
|
|
||||||
|
type SchemeFilter struct {
|
||||||
|
Type FilterType
|
||||||
|
Pattern string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SchemeFilter) Match(uri string) bool {
|
||||||
|
uriUpper := strings.ToUpper(uri)
|
||||||
|
patternUpper := strings.ToUpper(s.Pattern)
|
||||||
|
switch s.Type {
|
||||||
|
case FilterTypeUrl:
|
||||||
|
return strings.HasPrefix(uriUpper, patternUpper+":")
|
||||||
|
case FilterTypeFile:
|
||||||
|
return strings.HasSuffix(uriUpper, "."+patternUpper)
|
||||||
|
case FilterTypeBase64:
|
||||||
|
return strings.HasPrefix(uriUpper, "DATA:"+patternUpper+";BASE64,")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetcherManager manage and control the fetcher
|
||||||
|
type FetcherManager interface {
|
||||||
|
// Name return the name of the protocol.
|
||||||
|
Name() string
|
||||||
|
// Filters registers the supported schemes.
|
||||||
|
Filters() []*SchemeFilter
|
||||||
// Build returns a new fetcher.
|
// Build returns a new fetcher.
|
||||||
Build() Fetcher
|
Build() Fetcher
|
||||||
|
// ParseName name displayed when the task is not yet resolved, parsed from the request URL
|
||||||
|
ParseName(u string) string
|
||||||
|
// AutoRename returns whether the fetcher need renaming the download file when has the same name file.
|
||||||
|
AutoRename() bool
|
||||||
|
|
||||||
|
// DefaultConfig returns the default configuration of the protocol.
|
||||||
|
DefaultConfig() any
|
||||||
// Store fetcher
|
// Store fetcher
|
||||||
Store(fetcher Fetcher) (any, error)
|
Store(fetcher Fetcher) (any, error)
|
||||||
// Restore fetcher
|
// Restore fetcher
|
||||||
Restore() (v any, f func(meta *FetcherMeta, v any) Fetcher)
|
Restore() (v any, f func(meta *FetcherMeta, v any) Fetcher)
|
||||||
|
// Close the fetcher manager, release resources.
|
||||||
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultFetcher struct {
|
type DefaultFetcher struct {
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package fetcher
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSchemeFilter_Match(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
Type FilterType
|
||||||
|
Pattern string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
uri string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "url match",
|
||||||
|
fields: fields{
|
||||||
|
Type: FilterTypeUrl,
|
||||||
|
Pattern: "https",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
uri: "https://github.com",
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "url not match",
|
||||||
|
fields: fields{
|
||||||
|
Type: FilterTypeUrl,
|
||||||
|
Pattern: "https",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
uri: "ftp://github.com",
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file match",
|
||||||
|
fields: fields{
|
||||||
|
Type: FilterTypeFile,
|
||||||
|
Pattern: "torrent",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
uri: "d:/temp/test.torrent",
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file not match",
|
||||||
|
fields: fields{
|
||||||
|
Type: FilterTypeFile,
|
||||||
|
Pattern: "torrent",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
uri: "d:/temp/test.txt",
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "base64 match",
|
||||||
|
fields: fields{
|
||||||
|
Type: FilterTypeBase64,
|
||||||
|
Pattern: "application/x-bittorrent",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
uri: "data:application/x-bittorrent;base64,xxx",
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "base64 not match",
|
||||||
|
fields: fields{
|
||||||
|
Type: FilterTypeBase64,
|
||||||
|
Pattern: "application/x-bittorrent",
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
uri: "data:application/javascript;base64,xxx",
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
s := &SchemeFilter{
|
||||||
|
Type: tt.fields.Type,
|
||||||
|
Pattern: tt.fields.Pattern,
|
||||||
|
}
|
||||||
|
if got := s.Match(tt.args.uri); got != tt.want {
|
||||||
|
t.Errorf("Match() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,12 @@
|
|||||||
package bt
|
package bt
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Trackers []string `json:"trackers"`
|
ListenPort int `json:"listenPort"`
|
||||||
|
Trackers []string `json:"trackers"`
|
||||||
|
// SeedKeep is always keep seeding after downloading is complete, unless manually stopped.
|
||||||
|
SeedKeep bool `json:"seedKeep"`
|
||||||
|
// SeedRatio is the ratio of uploaded data to downloaded data to seed.
|
||||||
|
SeedRatio float64 `json:"seedRatio"`
|
||||||
|
// SeedTime is the time in seconds to seed after downloading is complete.
|
||||||
|
SeedTime int64 `json:"seedTime"`
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package bt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/dnscache"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DnsCacheResolver resolves DNS requests for an HTTP client using an in-memory cache.
|
||||||
|
type DnsCacheResolver struct {
|
||||||
|
RefreshTimeout time.Duration
|
||||||
|
|
||||||
|
resolver dnscache.Resolver
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DnsCacheResolver) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
|
host, port, err := net.SplitHostPort(address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ips, err := r.resolver.LookupHost(ctx, host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var conn net.Conn
|
||||||
|
for _, ip := range ips {
|
||||||
|
var dialer net.Dialer
|
||||||
|
conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip, port))
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *DnsCacheResolver) Run(ctx context.Context) {
|
||||||
|
ticker := time.NewTicker(r.RefreshTimeout)
|
||||||
|
defer ticker.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
r.resolver.Refresh(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+386
-104
File diff suppressed because it is too large.
Load diff
@@ -8,7 +8,10 @@ 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"
|
||||||
|
gohttp "net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -33,7 +36,6 @@ func TestFetcher_Resolve_DataUri_Torrent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
want := &base.Resource{
|
want := &base.Resource{
|
||||||
Name: "ubuntu-22.04-live-server-amd64.iso",
|
|
||||||
Size: 1466714112,
|
Size: 1466714112,
|
||||||
Range: true,
|
Range: true,
|
||||||
Files: []*base.FileInfo{
|
Files: []*base.FileInfo{
|
||||||
@@ -50,59 +52,188 @@ func TestFetcher_Resolve_DataUri_Torrent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFetcher_Config(t *testing.T) {
|
func TestFetcher_Config(t *testing.T) {
|
||||||
doResolve(t, buildConfigFetcher())
|
doResolve(t, buildConfigFetcher(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_ResolveWithProxy(t *testing.T) {
|
||||||
|
usr, pwd := "admin", "123"
|
||||||
|
proxyListener := test.StartSocks5Server(usr, pwd)
|
||||||
|
defer proxyListener.Close()
|
||||||
|
|
||||||
|
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) {
|
||||||
err := fetcher.Resolve(&base.Request{
|
t.Run("Resolve Single File", func(t *testing.T) {
|
||||||
URL: "./testdata/ubuntu-22.04-live-server-amd64.iso.torrent",
|
err := fetcher.Resolve(&base.Request{
|
||||||
Extra: bt.ReqExtra{
|
URL: "./testdata/ubuntu-22.04-live-server-amd64.iso.torrent",
|
||||||
Trackers: []string{
|
Extra: bt.ReqExtra{
|
||||||
"udp://tracker.birkenwald.de:6969/announce",
|
Trackers: []string{
|
||||||
"udp://tracker.bitsearch.to:1337/announce",
|
"udp://tracker.birkenwald.de:6969/announce",
|
||||||
|
"udp://tracker.bitsearch.to:1337/announce",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
})
|
if err != nil {
|
||||||
if err != nil {
|
panic(err)
|
||||||
panic(err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
want := &base.Resource{
|
want := &base.Resource{
|
||||||
Name: "ubuntu-22.04-live-server-amd64.iso",
|
Size: 1466714112,
|
||||||
Size: 1466714112,
|
Range: true,
|
||||||
Range: true,
|
Files: []*base.FileInfo{
|
||||||
Files: []*base.FileInfo{
|
{
|
||||||
{
|
Name: "ubuntu-22.04-live-server-amd64.iso",
|
||||||
Name: "ubuntu-22.04-live-server-amd64.iso",
|
Size: 1466714112,
|
||||||
Size: 1466714112,
|
},
|
||||||
},
|
},
|
||||||
},
|
Hash: "8a55cfbd5ca5d11507364765936c4f9e55b253ed",
|
||||||
Hash: "8a55cfbd5ca5d11507364765936c4f9e55b253ed",
|
}
|
||||||
|
if !reflect.DeepEqual(want, fetcher.Meta().Res) {
|
||||||
|
t.Errorf("Resolve Single File Resolve() got = %v, want %v", fetcher.Meta().Res, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Resolve Multi Files", func(t *testing.T) {
|
||||||
|
err := fetcher.Resolve(&base.Request{
|
||||||
|
URL: "./testdata/test.torrent",
|
||||||
|
Extra: bt.ReqExtra{
|
||||||
|
Trackers: []string{
|
||||||
|
"udp://tracker.birkenwald.de:6969/announce",
|
||||||
|
"udp://tracker.bitsearch.to:1337/announce",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := &base.Resource{
|
||||||
|
Name: "test",
|
||||||
|
Size: 107484864,
|
||||||
|
Range: true,
|
||||||
|
Files: []*base.FileInfo{
|
||||||
|
{
|
||||||
|
Name: "c.txt",
|
||||||
|
Path: "path",
|
||||||
|
Size: 98501754,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "b.txt",
|
||||||
|
Size: 8904996,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "a.txt",
|
||||||
|
Size: 78114,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Hash: "ccbc92b0cd8deec16a2ef4be242a8c9243b1cedb",
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(want, fetcher.Meta().Res) {
|
||||||
|
t.Errorf("Resolve Multi Files Resolve() got = %v, want %v", fetcher.Meta().Res, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Resolve Unclean Torrent", func(t *testing.T) {
|
||||||
|
err := fetcher.Resolve(&base.Request{
|
||||||
|
URL: "./testdata/test.unclean.torrent",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Resolve Unclean Torrent Resolve() got = %v, want nil", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Resolve file scheme Torrent", func(t *testing.T) {
|
||||||
|
file, _ := filepath.Abs("./testdata/test.unclean.torrent")
|
||||||
|
uri := "file:///" + file
|
||||||
|
err := fetcher.Resolve(&base.Request{
|
||||||
|
URL: uri,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Resolve file scheme Torrent Resolve() got = %v, want nil", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcherManager_ParseName(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(want, fetcher.Meta().Res) {
|
tests := []struct {
|
||||||
t.Errorf("Resolve() got = %v, want %v", fetcher.Meta().Res, want)
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "broken url",
|
||||||
|
args: args{
|
||||||
|
u: "magnet://!@#%github.com",
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dn",
|
||||||
|
args: args{
|
||||||
|
u: "magnet:?xt=urn:btih:8a55cfbd5ca5d11507364765936c4f9e55b253ed&dn=ubuntu-22.04-live-server-amd64.iso",
|
||||||
|
},
|
||||||
|
want: "ubuntu-22.04-live-server-amd64.iso",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no dn",
|
||||||
|
args: args{
|
||||||
|
u: "magnet:?xt=urn:btih:8a55cfbd5ca5d11507364765936c4f9e55b253ed",
|
||||||
|
},
|
||||||
|
want: "8a55cfbd5ca5d11507364765936c4f9e55b253ed",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non standard magnet",
|
||||||
|
args: args{
|
||||||
|
u: "magnet:?xxt=abcd",
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
fm := &FetcherManager{}
|
||||||
|
if got := fm.ParseName(tt.args.u); got != tt.want {
|
||||||
|
t.Errorf("ParseName() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFetcher() fetcher.Fetcher {
|
func buildFetcher() fetcher.Fetcher {
|
||||||
fetcher := new(FetcherBuilder).Build()
|
fb := new(FetcherManager)
|
||||||
fetcher.Setup(controller.NewController())
|
fetcher := fb.Build()
|
||||||
|
newController := controller.NewController()
|
||||||
|
newController.GetConfig = func(v any) {
|
||||||
|
json.Unmarshal([]byte(test.ToJson(fb.DefaultConfig())), v)
|
||||||
|
}
|
||||||
|
fetcher.Setup(newController)
|
||||||
return fetcher
|
return fetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConfigFetcher() fetcher.Fetcher {
|
func buildConfigFetcher(proxyConfig *base.DownloaderProxyConfig) fetcher.Fetcher {
|
||||||
fetcher := new(FetcherBuilder).Build()
|
fetcher := new(FetcherManager).Build()
|
||||||
newController := controller.NewController()
|
newController := controller.NewController()
|
||||||
mockCfg := config{
|
mockCfg := config{
|
||||||
Trackers: []string{
|
Trackers: []string{
|
||||||
"udp://tracker.birkenwald.de:6969/announce",
|
"udp://tracker.birkenwald.de:6969/announce",
|
||||||
"udp://tracker.bitsearch.to:1337/announce",
|
"udp://tracker.bitsearch.to:1337/announce",
|
||||||
}}
|
}}
|
||||||
newController.GetConfig = func(v any) (bool, error) {
|
newController.GetConfig = func(v any) {
|
||||||
if err := json.Unmarshal([]byte(test.ToJson(mockCfg)), v); err != nil {
|
json.Unmarshal([]byte(test.ToJson(mockCfg)), v)
|
||||||
return false, err
|
}
|
||||||
}
|
newController.GetProxy = func(requestProxy *base.RequestProxy) func(*gohttp.Request) (*url.URL, error) {
|
||||||
return true, nil
|
return proxyConfig.ToHandler()
|
||||||
}
|
}
|
||||||
fetcher.Setup(newController)
|
fetcher.Setup(newController)
|
||||||
return fetcher
|
return fetcher
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package bt
|
package bt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anacrolix/torrent/storage"
|
"github.com/anacrolix/torrent/storage"
|
||||||
"io"
|
"io"
|
||||||
@@ -33,7 +34,7 @@ func newFileOpts(opts newFileClientOpts) storage.ClientImplCloser {
|
|||||||
if opts.FilePathMaker == nil {
|
if opts.FilePathMaker == nil {
|
||||||
opts.FilePathMaker = func(opts storage.FilePathMakerOpts) string {
|
opts.FilePathMaker = func(opts storage.FilePathMakerOpts) string {
|
||||||
var parts []string
|
var parts []string
|
||||||
if opts.Info.Name != metainfo.NoName {
|
if opts.Info.Length == 0 {
|
||||||
parts = append(parts, opts.Info.Name)
|
parts = append(parts, opts.Info.Name)
|
||||||
}
|
}
|
||||||
return filepath.Join(append(parts, opts.File.Path...)...)
|
return filepath.Join(append(parts, opts.File.Path...)...)
|
||||||
@@ -53,7 +54,7 @@ func (fs fileClientImpl) Close() error {
|
|||||||
return fs.opts.PieceCompletion.Close()
|
return fs.opts.PieceCompletion.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs fileClientImpl) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (_ storage.TorrentImpl, err error) {
|
func (fs fileClientImpl) OpenTorrent(ctx context.Context, info *metainfo.Info, infoHash metainfo.Hash) (_ storage.TorrentImpl, err error) {
|
||||||
upvertedFiles := info.UpvertedFiles()
|
upvertedFiles := info.UpvertedFiles()
|
||||||
files := make([]file, 0, len(upvertedFiles))
|
files := make([]file, 0, len(upvertedFiles))
|
||||||
for _, fileInfo := range upvertedFiles {
|
for _, fileInfo := range upvertedFiles {
|
||||||
|
|||||||
BIN
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,7 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Connections int `json:"connections"`
|
UserAgent string `json:"userAgent"`
|
||||||
|
Connections int `json:"connections"`
|
||||||
|
UseServerCtime bool `json:"useServerCtime"`
|
||||||
}
|
}
|
||||||
+420
-162
File diff suppressed because it is too large.
Load diff
@@ -9,7 +9,9 @@ import (
|
|||||||
"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"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
gohttp "net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -35,6 +37,36 @@ func TestFetcher_Resolve(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, t)
|
}, t)
|
||||||
|
testResolve(test.StartTestCustomServer, "encoded-word", &base.Resource{
|
||||||
|
Size: test.BuildSize,
|
||||||
|
Range: false,
|
||||||
|
Files: []*base.FileInfo{
|
||||||
|
{
|
||||||
|
Name: "测试.zip",
|
||||||
|
Size: test.BuildSize,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, t)
|
||||||
|
testResolve(test.StartTestCustomServer, "no-encode", &base.Resource{
|
||||||
|
Size: test.BuildSize,
|
||||||
|
Range: false,
|
||||||
|
Files: []*base.FileInfo{
|
||||||
|
{
|
||||||
|
Name: "测试.zip",
|
||||||
|
Size: test.BuildSize,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, t)
|
||||||
|
testResolve(test.StartTestCustomServer, "%E6%B5%8B%E8%AF%95.zip", &base.Resource{
|
||||||
|
Size: 0,
|
||||||
|
Range: false,
|
||||||
|
Files: []*base.FileInfo{
|
||||||
|
{
|
||||||
|
Name: "测试.zip",
|
||||||
|
Size: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, t)
|
||||||
testResolve(test.StartTestCustomServer, test.BuildName, &base.Resource{
|
testResolve(test.StartTestCustomServer, test.BuildName, &base.Resource{
|
||||||
Size: 0,
|
Size: 0,
|
||||||
Range: false,
|
Range: false,
|
||||||
@@ -58,6 +90,36 @@ func TestFetcher_Resolve(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFetcher_ResolveWithHostHeader(t *testing.T) {
|
||||||
|
fetcher := buildFetcher()
|
||||||
|
err := fetcher.Resolve(&base.Request{
|
||||||
|
URL: "https://bing.com",
|
||||||
|
Extra: &http.ReqExtra{
|
||||||
|
Header: map[string]string{
|
||||||
|
"Host": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err == nil || !strings.Contains(err.Error(), "400") {
|
||||||
|
t.Errorf("Resolve() got = %v, want %v", err, "400")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_ResolveWithInvalidHeader(t *testing.T) {
|
||||||
|
fetcher := buildFetcher()
|
||||||
|
err := fetcher.Resolve(&base.Request{
|
||||||
|
URL: "https://bing.com",
|
||||||
|
Extra: &http.ReqExtra{
|
||||||
|
Header: map[string]string{
|
||||||
|
"Referer": "\rtest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Resolve() got = %v, want nil", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testResolve(startTestServer func() net.Listener, path string, want *base.Resource, t *testing.T) {
|
func testResolve(startTestServer func() net.Listener, path string, want *base.Resource, t *testing.T) {
|
||||||
listener := startTestServer()
|
listener := startTestServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
@@ -68,7 +130,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +138,7 @@ func testResolve(startTestServer func() net.Listener, path string, want *base.Re
|
|||||||
func TestFetcher_DownloadNormal(t *testing.T) {
|
func TestFetcher_DownloadNormal(t *testing.T) {
|
||||||
listener := test.StartTestFileServer()
|
listener := test.StartTestFileServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
// 正常下载
|
|
||||||
downloadNormal(listener, 1, t)
|
downloadNormal(listener, 1, t)
|
||||||
downloadNormal(listener, 5, t)
|
downloadNormal(listener, 5, t)
|
||||||
downloadNormal(listener, 8, t)
|
downloadNormal(listener, 8, t)
|
||||||
@@ -86,7 +148,7 @@ func TestFetcher_DownloadNormal(t *testing.T) {
|
|||||||
func TestFetcher_DownloadContinue(t *testing.T) {
|
func TestFetcher_DownloadContinue(t *testing.T) {
|
||||||
listener := test.StartTestFileServer()
|
listener := test.StartTestFileServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
// 暂停继续
|
|
||||||
downloadContinue(listener, 1, t)
|
downloadContinue(listener, 1, t)
|
||||||
downloadContinue(listener, 5, t)
|
downloadContinue(listener, 5, t)
|
||||||
downloadContinue(listener, 8, t)
|
downloadContinue(listener, 8, t)
|
||||||
@@ -96,7 +158,7 @@ func TestFetcher_DownloadContinue(t *testing.T) {
|
|||||||
func TestFetcher_DownloadChunked(t *testing.T) {
|
func TestFetcher_DownloadChunked(t *testing.T) {
|
||||||
listener := test.StartTestCustomServer()
|
listener := test.StartTestCustomServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
// chunked编码下载
|
|
||||||
downloadNormal(listener, 1, t)
|
downloadNormal(listener, 1, t)
|
||||||
downloadNormal(listener, 2, t)
|
downloadNormal(listener, 2, t)
|
||||||
}
|
}
|
||||||
@@ -104,24 +166,49 @@ func TestFetcher_DownloadChunked(t *testing.T) {
|
|||||||
func TestFetcher_DownloadPost(t *testing.T) {
|
func TestFetcher_DownloadPost(t *testing.T) {
|
||||||
listener := test.StartTestPostServer()
|
listener := test.StartTestPostServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
// post下载
|
|
||||||
downloadPost(listener, 1, t)
|
downloadPost(listener, 1, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetcher_DownloadRetry(t *testing.T) {
|
func TestFetcher_DownloadRetry(t *testing.T) {
|
||||||
listener := test.StartTestRetryServer()
|
listener := test.StartTestRetryServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
// chunked编码下载
|
|
||||||
downloadNormal(listener, 1, t)
|
downloadNormal(listener, 1, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetcher_DownloadError(t *testing.T) {
|
func TestFetcher_DownloadError(t *testing.T) {
|
||||||
listener := test.StartTestErrorServer()
|
listener := test.StartTestErrorServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
// chunked编码下载
|
|
||||||
downloadError(listener, 1, t)
|
downloadError(listener, 1, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadLimit(t *testing.T) {
|
||||||
|
listener := test.StartTestLimitServer(4, 0)
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
downloadNormal(listener, 1, t)
|
||||||
|
downloadNormal(listener, 2, t)
|
||||||
|
downloadNormal(listener, 8, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadResponseBodyReadTimeout(t *testing.T) {
|
||||||
|
listener := test.StartTestLimitServer(16, readTimeout.Milliseconds()+5000)
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
downloadError(listener, 1, t)
|
||||||
|
downloadError(listener, 4, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcher_DownloadOnBugFileServer(t *testing.T) {
|
||||||
|
listener := test.StartTestRangeBugServer()
|
||||||
|
defer listener.Close()
|
||||||
|
|
||||||
|
downloadNormal(listener, 1, t)
|
||||||
|
downloadNormal(listener, 4, t)
|
||||||
|
}
|
||||||
|
|
||||||
func TestFetcher_DownloadResume(t *testing.T) {
|
func TestFetcher_DownloadResume(t *testing.T) {
|
||||||
listener := test.StartTestFileServer()
|
listener := test.StartTestFileServer()
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
@@ -132,10 +219,21 @@ func TestFetcher_DownloadResume(t *testing.T) {
|
|||||||
downloadResume(listener, 16, t)
|
downloadResume(listener, 16, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFetcher_Config(t *testing.T) {
|
func TestFetcher_DownloadWithProxy(t *testing.T) {
|
||||||
|
httpListener := test.StartTestFileServer()
|
||||||
|
defer httpListener.Close()
|
||||||
|
proxyListener := test.StartSocks5Server("", "")
|
||||||
|
defer proxyListener.Close()
|
||||||
|
|
||||||
|
downloadWithProxy(httpListener, proxyListener, 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()
|
err := fetcher.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -151,6 +249,103 @@ func TestFetcher_Config(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
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_Stats(t *testing.T) {
|
||||||
|
listener := test.StartTestFileServer()
|
||||||
|
defer listener.Close()
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
stats := fetcher.Stats().(*http.Stats)
|
||||||
|
if len(stats.Connections) != 16 {
|
||||||
|
t.Errorf("Stats() got = %v, want %v", len(stats.Connections), 16)
|
||||||
|
}
|
||||||
|
totalDownloaded := int64(0)
|
||||||
|
for _, conn := range stats.Connections {
|
||||||
|
totalDownloaded += conn.Downloaded
|
||||||
|
}
|
||||||
|
if totalDownloaded != test.BuildSize {
|
||||||
|
t.Errorf("Stats() got = %v, want %v", totalDownloaded, test.BuildSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetcherManager_ParseName(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
u string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "broken url",
|
||||||
|
args: args{
|
||||||
|
u: "https://!@#%github.com",
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file path",
|
||||||
|
args: args{
|
||||||
|
u: "https://github.com/index.html",
|
||||||
|
},
|
||||||
|
want: "index.html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "file path with query and hash",
|
||||||
|
args: args{
|
||||||
|
u: "https://github.com/a/b/index.html/#list?name=1",
|
||||||
|
},
|
||||||
|
want: "index.html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no file path",
|
||||||
|
args: args{
|
||||||
|
u: "https://github.com",
|
||||||
|
},
|
||||||
|
want: "github.com",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
fm := &FetcherManager{}
|
||||||
|
if got := fm.ParseName(tt.args.u); got != tt.want {
|
||||||
|
t.Errorf("ParseName() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func downloadReady(listener net.Listener, connections int, t *testing.T) fetcher.Fetcher {
|
func downloadReady(listener net.Listener, connections int, t *testing.T) fetcher.Fetcher {
|
||||||
return doDownloadReady(buildFetcher(), listener, connections, t)
|
return doDownloadReady(buildFetcher(), listener, connections, t)
|
||||||
}
|
}
|
||||||
@@ -265,7 +460,7 @@ func downloadResume(listener net.Listener, connections int, t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fb := new(FetcherBuilder)
|
fb := new(FetcherManager)
|
||||||
time.Sleep(time.Millisecond * 50)
|
time.Sleep(time.Millisecond * 50)
|
||||||
data, err := fb.Store(fetcher)
|
data, err := fb.Store(fetcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -293,23 +488,48 @@ func downloadResume(listener net.Listener, connections int, t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func downloadWithProxy(httpListener net.Listener, proxyListener net.Listener, t *testing.T) {
|
||||||
|
fetcher := downloadReady(httpListener, 4, t)
|
||||||
|
ctl := controller.NewController()
|
||||||
|
ctl.GetProxy = func(requestProxy *base.RequestProxy) func(*gohttp.Request) (*url.URL, error) {
|
||||||
|
return (&base.DownloaderProxyConfig{
|
||||||
|
Enable: true,
|
||||||
|
Scheme: "socks5",
|
||||||
|
Host: proxyListener.Addr().String(),
|
||||||
|
}).ToHandler()
|
||||||
|
}
|
||||||
|
fetcher.Setup(ctl)
|
||||||
|
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 buildFetcher() *Fetcher {
|
func buildFetcher() *Fetcher {
|
||||||
fetcher := new(FetcherBuilder).Build()
|
fm := new(FetcherManager)
|
||||||
fetcher.Setup(controller.NewController())
|
fetcher := fm.Build()
|
||||||
|
newController := controller.NewController()
|
||||||
|
newController.GetConfig = func(v any) {
|
||||||
|
json.Unmarshal([]byte(test.ToJson(fm.DefaultConfig())), v)
|
||||||
|
}
|
||||||
|
fetcher.Setup(newController)
|
||||||
return fetcher.(*Fetcher)
|
return fetcher.(*Fetcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildConfigFetcher() fetcher.Fetcher {
|
func buildConfigFetcher(cfg config) fetcher.Fetcher {
|
||||||
fetcher := new(FetcherBuilder).Build()
|
fetcher := new(FetcherManager).Build()
|
||||||
newController := controller.NewController()
|
newController := controller.NewController()
|
||||||
mockCfg := config{
|
newController.GetConfig = func(v any) {
|
||||||
Connections: 16,
|
json.Unmarshal([]byte(test.ToJson(cfg)), v)
|
||||||
}
|
|
||||||
newController.GetConfig = func(v any) (bool, error) {
|
|
||||||
if err := json.Unmarshal([]byte(test.ToJson(mockCfg)), v); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
}
|
||||||
fetcher.Setup(newController)
|
fetcher.Setup(newController)
|
||||||
return fetcher
|
return fetcher
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TimeoutReader struct {
|
||||||
|
reader io.Reader
|
||||||
|
timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimeoutReader(r io.Reader, timeout time.Duration) *TimeoutReader {
|
||||||
|
return &TimeoutReader{
|
||||||
|
reader: r,
|
||||||
|
timeout: timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tr *TimeoutReader) Read(p []byte) (n int, err error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), tr.timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
var readErr error
|
||||||
|
var bytesRead int
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
bytesRead, readErr = tr.reader.Read(p)
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return bytesRead, readErr
|
||||||
|
case <-ctx.Done():
|
||||||
|
return 0, ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTimeoutReader_Read(t *testing.T) {
|
||||||
|
data := []byte("Hello, World!")
|
||||||
|
reader := bytes.NewReader(data)
|
||||||
|
timeoutReader := NewTimeoutReader(reader, 1*time.Second)
|
||||||
|
|
||||||
|
buf := make([]byte, len(data))
|
||||||
|
n, err := timeoutReader.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
if n != len(data) {
|
||||||
|
t.Fatalf("expected to read %d bytes, read %d", len(data), n)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(buf, data) {
|
||||||
|
t.Fatalf("expected %s, got %s", data, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeoutReader_ReadTimeout(t *testing.T) {
|
||||||
|
reader := &slowReader{delay: 2 * time.Second}
|
||||||
|
timeoutReader := NewTimeoutReader(reader, 1*time.Second)
|
||||||
|
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
_, err := timeoutReader.Read(buf)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected timeout error, got nil")
|
||||||
|
}
|
||||||
|
if !errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
t.Fatalf("expected %v, got %v", context.DeadlineExceeded, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type slowReader struct {
|
||||||
|
delay time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sr *slowReader) Read(p []byte) (n int, err error) {
|
||||||
|
time.Sleep(sr.delay)
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
Loaded 50 of 301 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user