mirror of
https://github.com/Xpl0itU/WiiUDownloader.git
synced 2025-05-09 13:52:02 -04:00
Revert aria2go changes
This commit is contained in:
parent
60ecc29424
commit
abdec05445
21 changed files with 92 additions and 1333 deletions
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
|
@ -25,7 +25,7 @@ jobs:
|
|||
msystem: UCRT64
|
||||
release: true
|
||||
update: true
|
||||
install: zip git mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-python mingw-w64-ucrt-x86_64-gtk3 mingw-w64-ucrt-x86_64-pkg-config mingw-w64-ucrt-x86_64-go mingw-w64-ucrt-x86_64-ntldd-git make
|
||||
install: zip git mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-python mingw-w64-ucrt-x86_64-gtk3 mingw-w64-ucrt-x86_64-pkg-config mingw-w64-ucrt-x86_64-go mingw-w64-ucrt-x86_64-ntldd-git
|
||||
- name: Build
|
||||
run: |
|
||||
python3 grabTitles.py
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -9,5 +9,3 @@ main
|
|||
*.a
|
||||
out/
|
||||
log.txt
|
||||
aria2-lib/
|
||||
_obj/
|
|
@ -1,8 +1,7 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive \
|
||||
PATH="$HOME/go/bin:/usr/local/go/bin:$PATH" \
|
||||
LD_LIBRARY_PATH="$LD_LIBRARY_PATH:pkg/aria2go/aria2-lib/lib"
|
||||
PATH="$HOME/go/bin:/usr/local/go/bin:$PATH"
|
||||
|
||||
RUN mkdir -p /usr/share/man/man1 /usr/share/man/man2 && \
|
||||
apt -y --no-install-recommends update && \
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
@ -27,12 +28,12 @@ func getCert(tmdData []byte, id int, numContents uint16) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func getDefaultCert(cancelCtx context.Context, progressReporter ProgressReporter, buffer []byte, ariaSessionPath string) ([]byte, error) {
|
||||
func getDefaultCert(cancelCtx context.Context, progressReporter ProgressReporter, client *http.Client, buffer []byte) ([]byte, error) {
|
||||
if len(cetkData) >= 0x350+0x300 {
|
||||
return cetkData[0x350 : 0x350+0x300], nil
|
||||
}
|
||||
cetkDir := path.Join(os.TempDir(), "cetk")
|
||||
if err := downloadFile(cancelCtx, progressReporter, "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/000500101000400a/cetk", cetkDir, true, buffer, ariaSessionPath); err != nil {
|
||||
if err := downloadFile(cancelCtx, progressReporter, client, "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/000500101000400a/cetk", cetkDir, true, buffer); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cetkData, err := os.ReadFile(cetkDir)
|
||||
|
@ -50,7 +51,7 @@ func getDefaultCert(cancelCtx context.Context, progressReporter ProgressReporter
|
|||
return nil, fmt.Errorf("failed to download OSv10 cetk, length: %d", len(cetkData))
|
||||
}
|
||||
|
||||
func GenerateCert(tmdData []byte, contentCount uint16, progressReporter ProgressReporter, cancelCtx context.Context, buffer []byte, ariaSessionPath string) (bytes.Buffer, error) {
|
||||
func GenerateCert(tmdData []byte, contentCount uint16, progressReporter ProgressReporter, client *http.Client, cancelCtx context.Context, buffer []byte) (bytes.Buffer, error) {
|
||||
cert := bytes.Buffer{}
|
||||
|
||||
cert0, err := getCert(tmdData, 0, contentCount)
|
||||
|
@ -65,7 +66,7 @@ func GenerateCert(tmdData []byte, contentCount uint16, progressReporter Progress
|
|||
}
|
||||
cert.Write(cert1)
|
||||
|
||||
defaultCert, err := getDefaultCert(cancelCtx, progressReporter, buffer, ariaSessionPath)
|
||||
defaultCert, err := getDefaultCert(cancelCtx, progressReporter, client, buffer)
|
||||
if err != nil {
|
||||
return bytes.Buffer{}, err
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
wiiudownloader "github.com/Xpl0itU/WiiUDownloader"
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
|
@ -40,15 +42,17 @@ func main() {
|
|||
logger.Fatal(err.Error())
|
||||
}
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "wiiudownloader")
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
MaxIdleConns: 1000,
|
||||
MaxIdleConnsPerHost: 1000,
|
||||
MaxConnsPerHost: 100,
|
||||
},
|
||||
Timeout: 30 * time.Second,
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
ariaSessionPath := filepath.Join(tmpDir, "wiiudownloader.session")
|
||||
|
||||
app.Connect("activate", func() {
|
||||
win := NewMainWindow(app, wiiudownloader.GetTitleEntries(wiiudownloader.TITLE_CATEGORY_GAME), logger, ariaSessionPath)
|
||||
win := NewMainWindow(app, wiiudownloader.GetTitleEntries(wiiudownloader.TITLE_CATEGORY_GAME), logger, client)
|
||||
win.ShowAll()
|
||||
app.AddWindow(win.window)
|
||||
app.GetActiveWindow().Show()
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
@ -39,10 +40,10 @@ type MainWindow struct {
|
|||
titles []wiiudownloader.TitleEntry
|
||||
decryptContents bool
|
||||
currentRegion uint8
|
||||
ariaSessionPath string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, logger *wiiudownloader.Logger, ariaSessionPath string) *MainWindow {
|
||||
func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, logger *wiiudownloader.Logger, client *http.Client) *MainWindow {
|
||||
gSettings, err := gtk.SettingsGetDefault()
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
|
@ -66,13 +67,13 @@ func NewMainWindow(app *gtk.Application, entries []wiiudownloader.TitleEntry, lo
|
|||
}
|
||||
|
||||
mainWindow := MainWindow{
|
||||
window: win,
|
||||
titles: entries,
|
||||
searchEntry: searchEntry,
|
||||
currentRegion: wiiudownloader.MCP_REGION_EUROPE | wiiudownloader.MCP_REGION_JAPAN | wiiudownloader.MCP_REGION_USA,
|
||||
logger: logger,
|
||||
lastSearchText: "",
|
||||
ariaSessionPath: ariaSessionPath,
|
||||
window: win,
|
||||
titles: entries,
|
||||
searchEntry: searchEntry,
|
||||
currentRegion: wiiudownloader.MCP_REGION_EUROPE | wiiudownloader.MCP_REGION_JAPAN | wiiudownloader.MCP_REGION_USA,
|
||||
logger: logger,
|
||||
lastSearchText: "",
|
||||
client: client,
|
||||
}
|
||||
|
||||
searchEntry.Connect("changed", mainWindow.onSearchEntryChanged)
|
||||
|
@ -264,7 +265,7 @@ func (mw *MainWindow) ShowAll() {
|
|||
|
||||
wiiudownloader.GenerateTicket(filepath.Join(parentDir, "title.tik"), titleID, titleKey, titleVersion)
|
||||
|
||||
cert, err := wiiudownloader.GenerateCert(tmdData, contentCount, mw.progressWindow, context.Background(), make([]byte, 0), mw.ariaSessionPath)
|
||||
cert, err := wiiudownloader.GenerateCert(tmdData, contentCount, mw.progressWindow, http.DefaultClient, context.Background(), make([]byte, 0))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -759,7 +760,7 @@ func (mw *MainWindow) onDownloadQueueClicked(selectedPath string) error {
|
|||
}
|
||||
tidStr := fmt.Sprintf("%016x", title.TitleID)
|
||||
titlePath := filepath.Join(selectedPath, fmt.Sprintf("%s [%s] [%s]", normalizeFilename(title.Name), wiiudownloader.GetFormattedKind(title.TitleID), tidStr))
|
||||
if err := wiiudownloader.DownloadTitle(queueCtx, tidStr, titlePath, mw.decryptContents, mw.progressWindow, mw.getDeleteEncryptedContents(), mw.logger, mw.ariaSessionPath); err != nil && err != context.Canceled {
|
||||
if err := wiiudownloader.DownloadTitle(queueCtx, tidStr, titlePath, mw.decryptContents, mw.progressWindow, mw.getDeleteEncryptedContents(), mw.logger, mw.client); err != nil && err != context.Canceled {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -3,15 +3,12 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
const smoothingFactor = 0.1
|
||||
|
||||
type ProgressWindow struct {
|
||||
Window *gtk.Window
|
||||
box *gtk.Box
|
||||
|
@ -22,8 +19,6 @@ type ProgressWindow struct {
|
|||
cancelFunc context.CancelFunc
|
||||
totalToDownload int64
|
||||
totalDownloaded int64
|
||||
lastUpdateTime time.Time
|
||||
averageSpeed float64
|
||||
}
|
||||
|
||||
func (pw *ProgressWindow) SetGameTitle(title string) {
|
||||
|
@ -40,19 +35,8 @@ func (pw *ProgressWindow) UpdateDownloadProgress(downloaded, speed int64, filePa
|
|||
pw.cancelButton.SetSensitive(true)
|
||||
currentDownload := downloaded + pw.totalDownloaded
|
||||
pw.bar.SetFraction(float64(currentDownload) / float64(pw.totalToDownload))
|
||||
|
||||
pw.averageSpeed = smoothingFactor*float64(speed) + (1-smoothingFactor)*pw.averageSpeed
|
||||
|
||||
pw.bar.SetText(fmt.Sprintf("Downloading %s (%s/%s) (%s/s)",
|
||||
filePath,
|
||||
humanize.Bytes(uint64(currentDownload)),
|
||||
humanize.Bytes(uint64(pw.totalToDownload)),
|
||||
humanize.Bytes(uint64(pw.averageSpeed)),
|
||||
))
|
||||
|
||||
pw.lastUpdateTime = time.Now()
|
||||
pw.bar.SetText(fmt.Sprintf("Downloading %s (%s/%s) (%s/s)", filePath, humanize.Bytes(uint64(currentDownload)), humanize.Bytes(uint64(pw.totalToDownload)), humanize.Bytes(uint64(speed))))
|
||||
})
|
||||
|
||||
for gtk.EventsPending() {
|
||||
gtk.MainIteration()
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>WiiUDownloader</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>2.30, Copyright 2022-2024 Xpl0itU</string>
|
||||
<string>2.29, Copyright 2022-2023 Xpl0itU</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>WiiUDownloader.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
@ -17,13 +17,13 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.30</string>
|
||||
<string>2.29</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.30</string>
|
||||
<string>2.29</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2022-2024 Xpl0itU, GNU General Public License.</string>
|
||||
<string>Copyright 2022-2023 Xpl0itU, GNU General Public License.</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>11.0</string>
|
||||
</dict>
|
||||
|
|
142
downloader.go
142
downloader.go
|
@ -8,14 +8,12 @@ import (
|
|||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/jaskaranSM/aria2go"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -35,38 +33,6 @@ type ProgressReporter interface {
|
|||
AddToTotalDownloaded(toAdd int64)
|
||||
}
|
||||
|
||||
type Aria2gocNotifier struct {
|
||||
start chan string
|
||||
complete chan bool
|
||||
}
|
||||
|
||||
func newAria2goNotifier(start chan string, complete chan bool) aria2go.Notifier {
|
||||
return Aria2gocNotifier{
|
||||
start: start,
|
||||
complete: complete,
|
||||
}
|
||||
}
|
||||
|
||||
func (n Aria2gocNotifier) OnStart(gid string) {
|
||||
n.start <- gid
|
||||
}
|
||||
|
||||
func (n Aria2gocNotifier) OnPause(gid string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (n Aria2gocNotifier) OnStop(gid string) {
|
||||
return
|
||||
}
|
||||
|
||||
func (n Aria2gocNotifier) OnComplete(gid string) {
|
||||
n.complete <- false
|
||||
}
|
||||
|
||||
func (n Aria2gocNotifier) OnError(gid string) {
|
||||
n.complete <- true
|
||||
}
|
||||
|
||||
func calculateDownloadSpeed(downloaded int64, startTime, endTime time.Time) int64 {
|
||||
duration := endTime.Sub(startTime).Seconds()
|
||||
if duration > 0 {
|
||||
|
@ -75,75 +41,73 @@ func calculateDownloadSpeed(downloaded int64, startTime, endTime time.Time) int6
|
|||
return 0
|
||||
}
|
||||
|
||||
func downloadFile(ctx context.Context, progressReporter ProgressReporter, downloadURL, dstPath string, doRetries bool, buffer []byte, ariaSessionPath string) error {
|
||||
fileName := filepath.Base(dstPath)
|
||||
func downloadFile(ctx context.Context, progressReporter ProgressReporter, client *http.Client, downloadURL, dstPath string, doRetries bool, buffer []byte) error {
|
||||
filePath := filepath.Base(dstPath)
|
||||
|
||||
var startTime time.Time
|
||||
|
||||
for attempt := 1; attempt <= maxRetries; attempt++ {
|
||||
client := aria2go.NewAria2(aria2go.Config{
|
||||
Options: aria2go.Options{
|
||||
"save-session": ariaSessionPath,
|
||||
},
|
||||
})
|
||||
|
||||
gid, err := client.AddUri(downloadURL, aria2go.Options{
|
||||
"dir": filepath.Dir(dstPath),
|
||||
"out": fileName,
|
||||
"continue": "true",
|
||||
})
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", downloadURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer client.Shutdown()
|
||||
client.Run()
|
||||
}()
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
startNotif := make(chan string)
|
||||
completeNotif := make(chan bool)
|
||||
go func() {
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
if doRetries && attempt < maxRetries {
|
||||
time.Sleep(retryDelay)
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("download error after %d attempts, status code: %d", attempt, resp.StatusCode)
|
||||
}
|
||||
|
||||
<-quit
|
||||
completeNotif <- true
|
||||
}()
|
||||
client.SetNotifier(newAria2goNotifier(startNotif, completeNotif))
|
||||
file, err := os.Create(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var downloaded int64
|
||||
|
||||
startTime = time.Now()
|
||||
ticker := time.NewTicker(time.Millisecond * 500)
|
||||
defer ticker.Stop()
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case id := <-startNotif:
|
||||
gid = id
|
||||
case <-ticker.C:
|
||||
downloaded := client.GetDownloadInfo(gid).BytesCompleted
|
||||
progressReporter.UpdateDownloadProgress(downloaded, calculateDownloadSpeed(downloaded, startTime, time.Now()), fileName)
|
||||
case errored := <-completeNotif:
|
||||
if errored {
|
||||
if doRetries && attempt < maxRetries {
|
||||
time.Sleep(retryDelay)
|
||||
break loop
|
||||
}
|
||||
return fmt.Errorf("write error after %d attempts: %+v", attempt, client.GetDownloadInfo(gid).ErrorCode)
|
||||
n, err := resp.Body.Read(buffer)
|
||||
if err != nil && err != io.EOF {
|
||||
if doRetries && attempt < maxRetries {
|
||||
time.Sleep(retryDelay)
|
||||
break
|
||||
}
|
||||
downloaded := client.GetDownloadInfo(gid).BytesCompleted
|
||||
progressReporter.UpdateDownloadProgress(downloaded, calculateDownloadSpeed(downloaded, startTime, time.Now()), fileName)
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
return fmt.Errorf("download error after %d attempts: %+v", attempt, err)
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
_, err = file.Write(buffer[:n])
|
||||
if err != nil {
|
||||
if doRetries && attempt < maxRetries {
|
||||
time.Sleep(retryDelay)
|
||||
break
|
||||
}
|
||||
return fmt.Errorf("write error after %d attempts: %+v", attempt, err)
|
||||
}
|
||||
|
||||
downloaded += int64(n)
|
||||
progressReporter.UpdateDownloadProgress(downloaded, calculateDownloadSpeed(downloaded, startTime, time.Now()), filePath)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, doDecryption bool, progressReporter ProgressReporter, deleteEncryptedContents bool, logger *Logger, ariaSessionPath string) error {
|
||||
func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, doDecryption bool, progressReporter ProgressReporter, deleteEncryptedContents bool, logger *Logger, client *http.Client) error {
|
||||
titleEntry := getTitleEntryFromTid(titleID)
|
||||
|
||||
progressReporter.SetTotalDownloaded(0)
|
||||
|
@ -163,7 +127,7 @@ func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, d
|
|||
buffer := make([]byte, bufferSize)
|
||||
|
||||
tmdPath := filepath.Join(outputDir, "title.tmd")
|
||||
if err := downloadFile(cancelCtx, progressReporter, fmt.Sprintf("%s/%s", baseURL, "tmd"), tmdPath, true, buffer, ariaSessionPath); err != nil {
|
||||
if err := downloadFile(cancelCtx, progressReporter, client, fmt.Sprintf("%s/%s", baseURL, "tmd"), tmdPath, true, buffer); err != nil {
|
||||
if progressReporter.Cancelled() {
|
||||
return nil
|
||||
}
|
||||
|
@ -181,7 +145,7 @@ func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, d
|
|||
}
|
||||
|
||||
tikPath := filepath.Join(outputDir, "title.tik")
|
||||
if err := downloadFile(cancelCtx, progressReporter, fmt.Sprintf("%s/%s", baseURL, "cetk"), tikPath, false, buffer, ariaSessionPath); err != nil {
|
||||
if err := downloadFile(cancelCtx, progressReporter, client, fmt.Sprintf("%s/%s", baseURL, "cetk"), tikPath, false, buffer); err != nil {
|
||||
if progressReporter.Cancelled() {
|
||||
return nil
|
||||
}
|
||||
|
@ -220,7 +184,7 @@ func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, d
|
|||
|
||||
progressReporter.SetDownloadSize(int64(titleSize))
|
||||
|
||||
cert, err := GenerateCert(tmdData, contentCount, progressReporter, cancelCtx, buffer, ariaSessionPath)
|
||||
cert, err := GenerateCert(tmdData, contentCount, progressReporter, client, cancelCtx, buffer)
|
||||
if err != nil {
|
||||
if progressReporter.Cancelled() {
|
||||
return nil
|
||||
|
@ -264,7 +228,7 @@ func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, d
|
|||
return err
|
||||
}
|
||||
filePath := filepath.Join(outputDir, fmt.Sprintf("%08X.app", id))
|
||||
if err := downloadFile(cancelCtx, progressReporter, fmt.Sprintf("%s/%08X", baseURL, id), filePath, true, buffer, ariaSessionPath); err != nil {
|
||||
if err := downloadFile(cancelCtx, progressReporter, client, fmt.Sprintf("%s/%08X", baseURL, id), filePath, true, buffer); err != nil {
|
||||
if progressReporter.Cancelled() {
|
||||
break
|
||||
}
|
||||
|
@ -274,7 +238,7 @@ func DownloadTitle(cancelCtx context.Context, titleID, outputDirectory string, d
|
|||
|
||||
if tmdData[offset+7]&0x2 == 2 {
|
||||
filePath = filepath.Join(outputDir, fmt.Sprintf("%08X.h3", id))
|
||||
if err := downloadFile(cancelCtx, progressReporter, fmt.Sprintf("%s/%08X.h3", baseURL, id), filePath, true, buffer, ariaSessionPath); err != nil {
|
||||
if err := downloadFile(cancelCtx, progressReporter, client, fmt.Sprintf("%s/%08X.h3", baseURL, id), filePath, true, buffer); err != nil {
|
||||
if progressReporter.Cancelled() {
|
||||
break
|
||||
}
|
||||
|
|
9
go.mod
9
go.mod
|
@ -9,15 +9,6 @@ require (
|
|||
golang.org/x/crypto v0.17.0
|
||||
)
|
||||
|
||||
require github.com/ianlancetaylor/cgosymbolizer v0.0.0-20231130194700-cfcb2fd150eb // indirect
|
||||
|
||||
require (
|
||||
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b // indirect
|
||||
github.com/jaskaranSM/aria2go v0.0.0-20210417130736-a4fd19b6cb10
|
||||
)
|
||||
|
||||
replace github.com/jaskaranSM/aria2go => ./pkg/aria2go
|
||||
|
||||
require (
|
||||
github.com/TheTitanrain/w32 v0.0.0-20200114052255-2654d97dbd3d // indirect
|
||||
golang.org/x/sync v0.5.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -2,14 +2,10 @@ github.com/TheTitanrain/w32 v0.0.0-20200114052255-2654d97dbd3d h1:2xp1BQbqcDDaik
|
|||
github.com/TheTitanrain/w32 v0.0.0-20200114052255-2654d97dbd3d/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I=
|
||||
github.com/Xpl0itU/dialog v0.0.0-20230805114139-ec888310aded h1:GkBw5aNvID1+SKAD3xC5fU4EwMgOmkrvICy5NX3Rqvw=
|
||||
github.com/Xpl0itU/dialog v0.0.0-20230805114139-ec888310aded/go.mod h1:Yl652wzqaetwEMJ8FnDRKBK1+CisE+PU5BGJXItbYFg=
|
||||
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b h1:5JgaFtHFRnOPReItxvhMDXbvuBkjSWE+9glJyF466yw=
|
||||
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b/go.mod h1:eMD2XUcPsHYbakFEocKrWZp47G0MRJYoC60qFblGjpA=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/gotk3/gotk3 v0.6.2 h1:sx/PjaKfKULJPTPq8p2kn2ZbcNFxpOJqi4VLzMbEOO8=
|
||||
github.com/gotk3/gotk3 v0.6.2/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q=
|
||||
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20231130194700-cfcb2fd150eb h1:asfjGoPvNgSPvgbBiwFqMUOgWgid8xlQGCGHfgM/PAs=
|
||||
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20231130194700-cfcb2fd150eb/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
|
|
|
@ -6,13 +6,11 @@ import ssl
|
|||
|
||||
# Don't edit below this line
|
||||
|
||||
|
||||
def checkAndDeleteFile(file):
|
||||
if os.path.exists(file):
|
||||
print(f"Deleting {file}")
|
||||
os.remove(file)
|
||||
|
||||
|
||||
# Disable certificate verification
|
||||
ssl_context = ssl.create_default_context()
|
||||
ssl_context.check_hostname = False
|
||||
|
@ -24,25 +22,13 @@ urllib.request.install_opener(opener)
|
|||
|
||||
checkAndDeleteFile("gtitles/gtitles.c")
|
||||
urllib.request.urlretrieve("https://napi.nbg01.v10lator.de/db", "gtitles/gtitles.c")
|
||||
os.system(
|
||||
"gcc -c -Wall -fpic -Ofast -pipe -Igtitles -o gtitles/gtitles.o gtitles/gtitles.c"
|
||||
)
|
||||
os.system("gcc -c -Wall -fpic -Ofast -pipe -Igtitles -o gtitles/gtitles.o gtitles/gtitles.c")
|
||||
os.system("ar rcs libgtitles.a gtitles/gtitles.o")
|
||||
os.system("gcc -shared -o gtitles/libgtitles.so gtitles/gtitles.o")
|
||||
|
||||
os.system(
|
||||
"gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/aes.o cdecrypt/aes.c"
|
||||
)
|
||||
os.system(
|
||||
"gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/cdecrypt.o cdecrypt/cdecrypt.c"
|
||||
)
|
||||
os.system(
|
||||
"gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/sha1.o cdecrypt/sha1.c"
|
||||
)
|
||||
os.system(
|
||||
"gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/util.o cdecrypt/util.c"
|
||||
)
|
||||
os.system("gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/aes.o cdecrypt/aes.c")
|
||||
os.system("gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/cdecrypt.o cdecrypt/cdecrypt.c")
|
||||
os.system("gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/sha1.o cdecrypt/sha1.c")
|
||||
os.system("gcc -c -Wall -fpic -Ofast -pipe -UNDEBUG -DAES_ROM_TABLES -D_GNU_SOURCE -Icdecrypt -o cdecrypt/util.o cdecrypt/util.c")
|
||||
os.system("ar rcs libcdecrypt.a cdecrypt/*.o")
|
||||
os.system("gcc -shared -o cdecrypt/libcdecrypt.so cdecrypt/*.o")
|
||||
|
||||
os.system("bash prepare_aria.sh")
|
||||
|
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2019 Vincent Chueng (coolingfall@gmail.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,323 +0,0 @@
|
|||
#include "aria2_c.h"
|
||||
#include "_cgo_export.h"
|
||||
#include <aria2/aria2.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
pthread_mutex_t access_mutex;
|
||||
|
||||
|
||||
|
||||
std::vector<std::string> splitBySemicolon(std::string in) {
|
||||
std::string val;
|
||||
std::stringstream is(in);
|
||||
std::vector<std::string> out;
|
||||
|
||||
while (getline(is, val, ';')) {
|
||||
out.push_back(val);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const char *toCStr(std::string in) {
|
||||
int len = in.length();
|
||||
char *val = new char[len + 1];
|
||||
memcpy(val, in.data(), len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
}
|
||||
|
||||
const char *getFileName(std::string dir, std::string path) {
|
||||
if (path.find(dir, 0) == std::string::npos) {
|
||||
return toCStr(path);
|
||||
}
|
||||
int index = dir.size();
|
||||
std::string name = path.substr(index + 1);
|
||||
return toCStr(name);
|
||||
}
|
||||
|
||||
const char *toAria2goOptions(aria2::KeyVals options) {
|
||||
std::vector<std::pair<std::string, std::string>>::iterator it;
|
||||
|
||||
std::string cOptions;
|
||||
for (it = options.begin(); it != options.end(); it++) {
|
||||
std::pair<std::string, std::string> p = *it;
|
||||
cOptions += p.first + ";" + p.second + ";";
|
||||
}
|
||||
|
||||
return toCStr(cOptions);
|
||||
}
|
||||
|
||||
aria2::KeyVals toAria2Options(const char *options) {
|
||||
aria2::KeyVals aria2Options;
|
||||
|
||||
if (options == nullptr) {
|
||||
return aria2Options;
|
||||
}
|
||||
|
||||
std::vector<std::string> o = splitBySemicolon(std::string(options));
|
||||
/* key and val should be pair */
|
||||
if (o.size() % 2 != 0) {
|
||||
return aria2Options;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)o.size(); i += 2) {
|
||||
std::string key = o[i];
|
||||
std::string val = o[i + 1];
|
||||
aria2Options.push_back(std::make_pair(key, val));
|
||||
}
|
||||
|
||||
return aria2Options;
|
||||
}
|
||||
|
||||
struct FileInfo *parseFileData(aria2::DownloadHandle *dh) {
|
||||
std::string dir = dh->getDir();
|
||||
std::vector<aria2::FileData> files = dh->getFiles();
|
||||
int numFiles = dh->getNumFiles();
|
||||
struct FileInfo *allFiles = new FileInfo[numFiles];
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
aria2::FileData file = files[i];
|
||||
struct FileInfo *fi = new FileInfo();
|
||||
fi->index = file.index;
|
||||
fi->name = getFileName(dir, file.path);
|
||||
fi->length = file.length;
|
||||
fi->completedLength = file.completedLength;
|
||||
fi->selected = file.selected;
|
||||
|
||||
allFiles[i] = *fi;
|
||||
delete fi;
|
||||
}
|
||||
return allFiles;
|
||||
}
|
||||
|
||||
/* retrieve all BitTorrent meta information */
|
||||
struct MetaInfo *parseMetaInfo(aria2::BtMetaInfoData btMetaInfo) {
|
||||
struct MetaInfo *mi = new MetaInfo();
|
||||
mi->name = toCStr(btMetaInfo.name);
|
||||
mi->comment = toCStr(btMetaInfo.comment);
|
||||
mi->creationUnix = btMetaInfo.creationDate;
|
||||
std::vector<std::vector<std::string>> announceList = btMetaInfo.announceList;
|
||||
std::vector<std::vector<std::string>>::iterator it;
|
||||
std::string cAnnounceList;
|
||||
for (it = announceList.begin(); it != announceList.end(); it++) {
|
||||
std::vector<std::string>::iterator cit;
|
||||
std::vector<std::string> childList = *it;
|
||||
for (cit = childList.begin(); cit != childList.end(); cit++) {
|
||||
cAnnounceList += *cit;
|
||||
if (it != announceList.end() - 1 || cit != childList.end() - 1) {
|
||||
cAnnounceList += ";";
|
||||
}
|
||||
}
|
||||
}
|
||||
mi->announceList = toCStr(cAnnounceList);
|
||||
return mi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global aria2 session.
|
||||
*/
|
||||
aria2::Session *session;
|
||||
/**
|
||||
* Global aria2go go pointer.
|
||||
*/
|
||||
uint64_t aria2goPointer;
|
||||
|
||||
/**
|
||||
* Download event callback for aria2.
|
||||
*/
|
||||
int downloadEventCallback(aria2::Session *session, aria2::DownloadEvent event,
|
||||
const aria2::A2Gid gid, void *userData) {
|
||||
notifyEvent(aria2goPointer, gid, event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initial aria2 library.
|
||||
*/
|
||||
int init(uint64_t pointer, const char *options) {
|
||||
aria2goPointer = pointer;
|
||||
int ret = aria2::libraryInit();
|
||||
aria2::SessionConfig config;
|
||||
config.keepRunning = true;
|
||||
/* do not use signal handler, cause c will block go */
|
||||
config.useSignalHandler = false;
|
||||
config.downloadEventCallback = downloadEventCallback;
|
||||
session = aria2::sessionNew(toAria2Options(options), config);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown schedules. This will cause run finished.
|
||||
*/
|
||||
int shutdownSchedules(bool force) { return aria2::shutdown(session, force); }
|
||||
|
||||
/**
|
||||
* Deinit aria2 library, this must be invoked when process exit(signal handler
|
||||
* is not used), so aria2 will be able to save session config.
|
||||
*/
|
||||
int deinit() {
|
||||
int ret = aria2::sessionFinal(session);
|
||||
session = nullptr;
|
||||
aria2::libraryDeinit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new HTTP(S)/FTP/BitTorrent Magnet URI. See `addUri` in aria2.
|
||||
*
|
||||
* @param uri uri to add
|
||||
*/
|
||||
uint64_t addUri(char *uri, const char *options) {
|
||||
std::vector<std::string> uris = {uri};
|
||||
aria2::A2Gid gid;
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
int ret = aria2::addUri(session, &gid, uris, toAria2Options(options));
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bit torrent file. See `addTorrent` in aria2.
|
||||
*/
|
||||
uint64_t addTorrent(char *fp, const char *options) {
|
||||
aria2::A2Gid gid;
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
int ret = aria2::addTorrent(session, &gid, fp, toAria2Options(options));
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change aria2 options. See `changeOption` in aria2.
|
||||
*/
|
||||
bool changeOptions(uint64_t gid, const char *options) {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
bool ret = aria2::changeOption(session, gid, toAria2Options(options)) == 0;
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options for given gid. see `getOptions` in aria2.
|
||||
*/
|
||||
const char *getOptions(uint64_t gid) {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
aria2::DownloadHandle *dh = aria2::getDownloadHandle(session, gid);
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
if (!dh) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return toAria2goOptions(dh->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Change global options. See `changeGlobalOption` in aria2.
|
||||
*/
|
||||
bool changeGlobalOptions(const char *options) {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
bool ret = aria2::changeGlobalOption(session, toAria2Options(options));
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get global options. see `getGlobalOptions` in aria2.
|
||||
*/
|
||||
const char *getGlobalOptions() {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
aria2::KeyVals options = aria2::getGlobalOptions(session);
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
return toAria2goOptions(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs event polling and actions for them.
|
||||
*/
|
||||
int run() { return aria2::run(session, aria2::RUN_DEFAULT); }
|
||||
|
||||
/**
|
||||
* Pause an active download with given gid. This will mark the download to
|
||||
* `DOWNLOAD_PAUSED`. See `resume`.
|
||||
*/
|
||||
bool pause(uint64_t gid) {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
bool ret = aria2::pauseDownload(session, gid) == 0;
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume a paused download with given gid. See `pause`.
|
||||
*/
|
||||
bool resume(uint64_t gid) {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
bool ret = aria2::unpauseDownload(session, gid) == 0;
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a download in queue with given gid. This will stop downloading and
|
||||
* seeding(for torrent).
|
||||
*/
|
||||
bool removeDownload(uint64_t gid) {
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
bool ret = aria2::removeDownload(session, gid) == 0;
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get download information for current download with given gid.
|
||||
*/
|
||||
struct DownloadInfo *getDownloadInfo(uint64_t gid) {
|
||||
if (session == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
pthread_mutex_lock(&access_mutex);
|
||||
aria2::DownloadHandle *dh = aria2::getDownloadHandle(session, gid);
|
||||
pthread_mutex_unlock(&access_mutex);
|
||||
if (!dh) {
|
||||
return nullptr;
|
||||
}
|
||||
struct DownloadInfo *di = new DownloadInfo();
|
||||
di->status = dh->getStatus();
|
||||
di->totalLength = dh->getTotalLength();
|
||||
di->bytesCompleted = dh->getCompletedLength();
|
||||
di->uploadLength = dh->getUploadLength();
|
||||
di->downloadSpeed = dh->getDownloadSpeed();
|
||||
di->uploadSpeed = dh->getUploadSpeed();
|
||||
di->pieceLength = dh->getPieceLength();
|
||||
di->numPieces = dh->getNumPieces();
|
||||
di->connections = dh->getConnections();
|
||||
di->numFiles = dh->getNumFiles();
|
||||
di->infoHash = toCStr(dh->getInfoHash());
|
||||
di->metaInfo = parseMetaInfo(dh->getBtMetaInfo());
|
||||
di->files = parseFileData(dh);
|
||||
di->errorCode = dh->getErrorCode();
|
||||
std::vector<aria2::A2Gid> gids = dh->getFollowedBy();
|
||||
if (gids.size() != 0) {
|
||||
di->followedByGid = gids[0];
|
||||
} else {
|
||||
di->followedByGid = 0;
|
||||
}
|
||||
// std::cout << "status" << dh->getStatus() << std::endl;
|
||||
// std::cout << "Error: " << dh->getErrorCode() << std::endl;
|
||||
// std::cout << "Completed: " << dh->getCompletedLength() << std::endl;
|
||||
// std::cout << "Total: " << dh->getTotalLength() << std::endl;
|
||||
/* delete download handle */
|
||||
aria2::deleteDownloadHandle(dh);
|
||||
return di;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#ifndef ARIA2_C_H
|
||||
#define ARIA2_C_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type definition for file information in torrent.
|
||||
*/
|
||||
struct FileInfo {
|
||||
int index;
|
||||
const char *name;
|
||||
int64_t length;
|
||||
int64_t completedLength;
|
||||
bool selected;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type definition for BitTorrent meta information.
|
||||
*/
|
||||
struct MetaInfo {
|
||||
const char *name;
|
||||
const char *comment;
|
||||
int64_t creationUnix;
|
||||
const char *announceList;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type definition for download information.
|
||||
*/
|
||||
struct DownloadInfo {
|
||||
int status;
|
||||
int64_t totalLength;
|
||||
int64_t bytesCompleted;
|
||||
int64_t uploadLength;
|
||||
int downloadSpeed;
|
||||
int uploadSpeed;
|
||||
int pieceLength;
|
||||
int numPieces;
|
||||
int connections;
|
||||
int numFiles;
|
||||
const char *infoHash;
|
||||
struct MetaInfo *metaInfo;
|
||||
struct FileInfo *files;
|
||||
int errorCode;
|
||||
uint64_t followedByGid;
|
||||
};
|
||||
|
||||
int init(uint64_t aria2goPointer, const char *options);
|
||||
int shutdownSchedules(bool force);
|
||||
int deinit();
|
||||
uint64_t addUri(char *uri, const char *options);
|
||||
uint64_t addTorrent(char *fp, const char *options);
|
||||
bool changeOptions(uint64_t gid, const char *options);
|
||||
const char *getOptions(uint64_t gid);
|
||||
bool changeGlobalOptions(const char *options);
|
||||
const char *getGlobalOptions();
|
||||
int run();
|
||||
bool pause(uint64_t gid);
|
||||
bool resume(uint64_t gid);
|
||||
bool removeDownload(uint64_t gid);
|
||||
struct DownloadInfo *getDownloadInfo(uint64_t gid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,7 +0,0 @@
|
|||
module github.com/jaskaranSM/aria2go
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b // indirect
|
||||
)
|
|
@ -1,2 +0,0 @@
|
|||
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b h1:5JgaFtHFRnOPReItxvhMDXbvuBkjSWE+9glJyF466yw=
|
||||
github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b/go.mod h1:eMD2XUcPsHYbakFEocKrWZp47G0MRJYoC60qFblGjpA=
|
|
@ -1,333 +0,0 @@
|
|||
// Copyright (C) 2019 Vincent Chueng (coolingfall@gmail.com).
|
||||
|
||||
package aria2go
|
||||
|
||||
/*
|
||||
#cgo CXXFLAGS: -std=c++11 -I./aria2-lib/include -Werror -Wall
|
||||
#cgo LDFLAGS: -L./aria2-lib/lib
|
||||
#cgo LDFLAGS: -laria2 -lcares -lssl -lcrypto
|
||||
#cgo darwin LDFLAGS: -framework Security
|
||||
#cgo windows LDFLAGS: -lws2_32 -lwsock32 -lgdi32 -lwinmm -liphlpapi -lpsapi -lcrypt32 -lsecur32 -ladvapi32
|
||||
#include <stdlib.h>
|
||||
#include "aria2_c.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
_ "github.com/benesch/cgosymbolizer"
|
||||
)
|
||||
|
||||
// Type definition for lib aria2, it holds a notifier.
|
||||
type Aria2 struct {
|
||||
notifier Notifier
|
||||
shutdownNotification chan bool
|
||||
shouldShutdown bool
|
||||
m_mutex sync.Mutex
|
||||
}
|
||||
|
||||
// Type definition of configuration for aria2.
|
||||
type Config struct {
|
||||
Options Options
|
||||
Notifier Notifier
|
||||
}
|
||||
|
||||
// NewAria2 creates a new instance of aria2.
|
||||
func NewAria2(config Config) *Aria2 {
|
||||
a := &Aria2{
|
||||
notifier: newDefaultNotifier(),
|
||||
shutdownNotification: make(chan bool),
|
||||
}
|
||||
a.SetNotifier(config.Notifier)
|
||||
|
||||
C.init(C.uint64_t(uintptr(unsafe.Pointer(a))),
|
||||
C.CString(a.fromOptions(config.Options)))
|
||||
return a
|
||||
}
|
||||
|
||||
// Shutdown aria2, this must be invoked when process exit(signal handler is not
|
||||
// used), so aria2 will be able to save session config.
|
||||
func (a *Aria2) Shutdown() int {
|
||||
C.shutdownSchedules(true)
|
||||
a.shouldShutdown = true
|
||||
|
||||
// do nothing, just make thread waiting
|
||||
select {
|
||||
case <-a.shutdownNotification:
|
||||
break
|
||||
}
|
||||
|
||||
return int(C.deinit())
|
||||
}
|
||||
|
||||
// Run starts event pooling. Note this will block current thread.
|
||||
func (a *Aria2) Run() {
|
||||
for {
|
||||
if C.run() != 1 && a.shouldShutdown {
|
||||
break
|
||||
}
|
||||
}
|
||||
a.shutdownNotification <- true
|
||||
}
|
||||
|
||||
// SetNotifier sets notifier to receive download notification from aria2.
|
||||
func (a *Aria2) SetNotifier(notifier Notifier) {
|
||||
if notifier == nil {
|
||||
return
|
||||
}
|
||||
a.notifier = notifier
|
||||
}
|
||||
|
||||
// AddUri adds a new download. The uris is an array of HTTP/FTP/SFTP/BitTorrent
|
||||
// URIs (strings) pointing to the same resource. When adding BitTorrent Magnet
|
||||
// URIs, uris must have only one element and it should be BitTorrent Magnet URI.
|
||||
func (a *Aria2) AddUri(uri string, options Options) (gid string, err error) {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
cUri := C.CString(uri)
|
||||
cOptions := C.CString(a.fromOptions(options))
|
||||
defer C.free(unsafe.Pointer(cUri))
|
||||
defer C.free(unsafe.Pointer(cOptions))
|
||||
|
||||
ret := C.addUri(cUri, cOptions)
|
||||
if ret == 0 {
|
||||
return "", errors.New("libaria2: add uri failed")
|
||||
}
|
||||
return fmt.Sprintf("%x", uint64(ret)), nil
|
||||
}
|
||||
|
||||
// AddTorrent adds a MetaInfo download with given torrent file path.
|
||||
// This will return gid and files in torrent file if add successfully.
|
||||
// User can choose specified files to download, change directory and so on.
|
||||
func (a *Aria2) AddTorrent(filepath string, options Options) (gid string, err error) {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
cFilepath := C.CString(filepath)
|
||||
cOptions := C.CString(a.fromOptions(options))
|
||||
defer C.free(unsafe.Pointer(cFilepath))
|
||||
defer C.free(unsafe.Pointer(cOptions))
|
||||
|
||||
ret := C.addTorrent(cFilepath, cOptions)
|
||||
if ret == 0 {
|
||||
return "", errors.New("libaria2: add torrent failed")
|
||||
}
|
||||
return fmt.Sprintf("%x", uint64(ret)), nil
|
||||
}
|
||||
|
||||
// ChangeOptions can change the options for aria2. See available options in
|
||||
// https://aria2.github.io/manual/en/html/aria2c.html#input-file.
|
||||
func (a *Aria2) ChangeOptions(gid string, options Options) error {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
cOptions := C.CString(a.fromOptions(options))
|
||||
defer C.free(unsafe.Pointer(cOptions))
|
||||
|
||||
if !C.changeOptions(a.hexToGid(gid), cOptions) {
|
||||
return errors.New("libaria2: change options error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOptions gets all options for given gid.
|
||||
func (a *Aria2) GetOptions(gid string) Options {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
cOptions := C.getOptions(a.hexToGid(gid))
|
||||
if cOptions == nil {
|
||||
return make(Options)
|
||||
}
|
||||
|
||||
return a.toOptions(C.GoString(cOptions))
|
||||
}
|
||||
|
||||
// ChangeGlobalOptions changes global options. See available options in
|
||||
// https://aria2.github.io/manual/en/html/aria2c.html#input-file except for
|
||||
// `checksum`, `index-out`, `out`, `pause` and `select-file`.
|
||||
func (a *Aria2) ChangeGlobalOptions(options Options) error {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
cOptions := C.CString(a.fromOptions(options))
|
||||
defer C.free(unsafe.Pointer(cOptions))
|
||||
|
||||
if !C.changeGlobalOptions(cOptions) {
|
||||
return errors.New("libaria2: change global options error")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetGlobalOptions gets all global options of aria2.
|
||||
func (a *Aria2) GetGlobalOptions() Options {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
return a.toOptions(C.GoString(C.getGlobalOptions()))
|
||||
}
|
||||
|
||||
// Pause pauses an active download for given gid. The status of the download
|
||||
// will become `DOWNLOAD_PAUSED`. Use `Resume` to restart download.
|
||||
func (a *Aria2) Pause(gid string) bool {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
return bool(C.pause(a.hexToGid(gid)))
|
||||
}
|
||||
|
||||
// Resume resumes an paused download for given gid.
|
||||
func (a *Aria2) Resume(gid string) bool {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
return bool(C.resume(a.hexToGid(gid)))
|
||||
}
|
||||
|
||||
// Remove removes download no matter what status it was. This will stop
|
||||
// downloading and stop seeding(for torrent).
|
||||
func (a *Aria2) Remove(gid string) bool {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
return bool(C.removeDownload(a.hexToGid(gid)))
|
||||
}
|
||||
|
||||
// GetDownloadInfo gets current download information for given gid.
|
||||
func (a *Aria2) GetDownloadInfo(gid string) DownloadInfo {
|
||||
a.m_mutex.Lock()
|
||||
defer a.m_mutex.Unlock()
|
||||
ret := C.getDownloadInfo(a.hexToGid(gid))
|
||||
if ret == nil {
|
||||
return DownloadInfo{}
|
||||
}
|
||||
defer C.free(unsafe.Pointer(ret))
|
||||
|
||||
// convert info hash to hex string
|
||||
infoHash := fmt.Sprintf("%x", []byte(C.GoString(ret.infoHash)))
|
||||
C.free(unsafe.Pointer(ret.infoHash))
|
||||
// retrieve BitTorrent meta information
|
||||
var metaInfo = MetaInfo{}
|
||||
mi := ret.metaInfo
|
||||
defer C.free(unsafe.Pointer(mi))
|
||||
if mi != nil {
|
||||
announceList := strings.Split(C.GoString(mi.announceList), ";")
|
||||
metaInfo = MetaInfo{
|
||||
Name: C.GoString(mi.name),
|
||||
Comment: C.GoString(mi.comment),
|
||||
CreationUnix: int64(mi.creationUnix),
|
||||
AnnounceList: announceList,
|
||||
}
|
||||
C.free(unsafe.Pointer(mi.name))
|
||||
C.free(unsafe.Pointer(mi.comment))
|
||||
C.free(unsafe.Pointer(mi.announceList))
|
||||
}
|
||||
return DownloadInfo{
|
||||
Status: int(ret.status),
|
||||
TotalLength: int64(ret.totalLength),
|
||||
BytesCompleted: int64(ret.bytesCompleted),
|
||||
BytesUpload: int64(ret.uploadLength),
|
||||
DownloadSpeed: int(ret.downloadSpeed),
|
||||
UploadSpeed: int(ret.uploadSpeed),
|
||||
NumPieces: int(ret.numPieces),
|
||||
Connections: int(ret.connections),
|
||||
InfoHash: infoHash,
|
||||
MetaInfo: metaInfo,
|
||||
Files: a.parseFiles(ret.files, ret.numFiles),
|
||||
ErrorCode: int(ret.errorCode),
|
||||
FollowedByGid: fmt.Sprintf("%x", uint64(ret.followedByGid)),
|
||||
}
|
||||
}
|
||||
|
||||
// fromOptions converts `Options` to string with ';' separator.
|
||||
func (a *Aria2) fromOptions(options Options) string {
|
||||
if options == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var cOptions string
|
||||
for k, v := range options {
|
||||
cOptions += k + ";"
|
||||
cOptions += v + ";"
|
||||
}
|
||||
|
||||
return strings.TrimSuffix(cOptions, ";")
|
||||
}
|
||||
|
||||
// fromOptions converts options string with ';' separator to `Options`.
|
||||
func (a *Aria2) toOptions(cOptions string) Options {
|
||||
coptions := strings.Split(strings.TrimSuffix(cOptions, ";"), ";")
|
||||
var options = make(Options)
|
||||
var index int
|
||||
for index = 0; index < len(coptions); index += 2 {
|
||||
options[coptions[index]] = coptions[index+1]
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// hexToGid convert hex to uint64 type gid.
|
||||
func (a *Aria2) hexToGid(hex string) C.uint64_t {
|
||||
id, err := strconv.ParseUint(hex, 16, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return C.uint64_t(id)
|
||||
}
|
||||
|
||||
// parseFiles parses all files information from aria2.
|
||||
func (a *Aria2) parseFiles(filesPointer *C.struct_FileInfo, length C.int) (files []File) {
|
||||
cfiles := (*[1 << 20]C.struct_FileInfo)(unsafe.Pointer(filesPointer))[:length:length]
|
||||
if cfiles == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, f := range cfiles {
|
||||
files = append(files, File{
|
||||
Index: int(f.index),
|
||||
Length: int64(f.length),
|
||||
CompletedLength: int64(f.completedLength),
|
||||
Name: C.GoString(f.name),
|
||||
Selected: bool(f.selected),
|
||||
})
|
||||
C.free(unsafe.Pointer(f.name))
|
||||
}
|
||||
|
||||
// free c pointer resource
|
||||
C.free(unsafe.Pointer(filesPointer))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// noinspection GoUnusedFunction
|
||||
//
|
||||
//export notifyEvent
|
||||
func notifyEvent(ariagoPointer uint64, id uint64, event int) {
|
||||
a := (*Aria2)(unsafe.Pointer(uintptr(ariagoPointer)))
|
||||
if a == nil || a.notifier == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// convert id to hex string
|
||||
gid := fmt.Sprintf("%x", uint64(id))
|
||||
|
||||
switch event {
|
||||
case onStart:
|
||||
a.notifier.OnStart(gid)
|
||||
case onPause:
|
||||
a.notifier.OnPause(gid)
|
||||
case onStop:
|
||||
a.notifier.OnStop(gid)
|
||||
case onComplete:
|
||||
a.notifier.OnComplete(gid)
|
||||
case onError:
|
||||
a.notifier.OnError(gid)
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection GoUnusedFunction
|
||||
//
|
||||
//export goLog
|
||||
func goLog(msg *C.char) {
|
||||
log.Println(C.GoString(msg))
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (C) 2019 Vincent Chueng (coolingfall@gmail.com).
|
||||
|
||||
package aria2go
|
||||
|
||||
// Type definition for download information.
|
||||
type DownloadInfo struct {
|
||||
Status int
|
||||
TotalLength int64
|
||||
BytesCompleted int64
|
||||
BytesUpload int64
|
||||
DownloadSpeed int
|
||||
UploadSpeed int
|
||||
NumPieces int
|
||||
Connections int
|
||||
BitField string
|
||||
InfoHash string
|
||||
MetaInfo MetaInfo
|
||||
Files []File
|
||||
ErrorCode int
|
||||
FollowedByGid string
|
||||
}
|
||||
|
||||
// Type definition for BitTorrent meta information.
|
||||
type MetaInfo struct {
|
||||
Name string
|
||||
AnnounceList []string
|
||||
Comment string
|
||||
CreationUnix int64
|
||||
Mode string
|
||||
}
|
||||
|
||||
// Type definition for file in torrent.
|
||||
type File struct {
|
||||
Index int
|
||||
Name string
|
||||
Length int64
|
||||
CompletedLength int64
|
||||
Selected bool
|
||||
}
|
||||
|
||||
type Options map[string]string
|
||||
|
||||
// Type definition for download event, this will keep the same with aria2.
|
||||
const (
|
||||
onStart = iota + 1
|
||||
onPause
|
||||
onStop
|
||||
onComplete
|
||||
onError
|
||||
onBTComplete
|
||||
)
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (C) 2019 Vincent Chueng (coolingfall@gmail.com).
|
||||
|
||||
package aria2go
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Type definition for notifier which can be used in aria2c json rpc notification.
|
||||
type Notifier interface {
|
||||
// OnStart will be invoked when aria2 started to download
|
||||
OnStart(gid string)
|
||||
|
||||
// OnPause will be invoked when aria2 paused one download
|
||||
OnPause(gid string)
|
||||
|
||||
// OnPause will be invoked when aria2 stopped one download
|
||||
OnStop(gid string)
|
||||
|
||||
// OnComplete will be invoked when download completed
|
||||
OnComplete(gid string)
|
||||
|
||||
// OnError will be invoked when an error occoured
|
||||
OnError(gid string)
|
||||
}
|
||||
|
||||
// Type definition for default notifier which dose nothing.
|
||||
type DefaultNotifier struct{}
|
||||
|
||||
// newDefaultNotifier creates a new instance of default Notifier.
|
||||
func newDefaultNotifier() Notifier {
|
||||
return DefaultNotifier{}
|
||||
}
|
||||
|
||||
// OnStart implements Notifier interface.
|
||||
func (n DefaultNotifier) OnStart(gid string) {
|
||||
log.Printf("on start %v", gid)
|
||||
}
|
||||
|
||||
// OnPause implements Notifier interface.
|
||||
func (n DefaultNotifier) OnPause(gid string) {
|
||||
log.Printf("on pause: %v", gid)
|
||||
}
|
||||
|
||||
// OnPause implements Notifier interface.
|
||||
func (n DefaultNotifier) OnStop(gid string) {
|
||||
log.Printf("on stop: %v", gid)
|
||||
}
|
||||
|
||||
// OnComplete implements Notifier interface.
|
||||
func (n DefaultNotifier) OnComplete(gid string) {
|
||||
log.Printf("on complete: %v", gid)
|
||||
}
|
||||
|
||||
// OnError implements Notifier interface.
|
||||
func (n DefaultNotifier) OnError(gid string) {
|
||||
log.Printf("on error: %v", gid)
|
||||
}
|
118
prepare_aria.sh
118
prepare_aria.sh
|
@ -1,118 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# In this configuration, the following dependent libraries are compiled:
|
||||
#
|
||||
# * c-ares
|
||||
# * openSSL
|
||||
|
||||
# Compiler and path
|
||||
PREFIX=$PWD/pkg/aria2go/aria2-lib
|
||||
C_COMPILER="gcc"
|
||||
CXX_COMPILER="g++"
|
||||
|
||||
NPROC=`nproc`
|
||||
# check if nproc is a command
|
||||
if ! [[ -x "$(command -v nproc)" ]]; then
|
||||
echo 'Error: nproc is not installed. Using sysctl for macOS' >&2
|
||||
$NPROC=`sysctl -n hw.logicalcpu` # macOS
|
||||
fi
|
||||
|
||||
# Check tool for download
|
||||
aria2c --help > /dev/null
|
||||
if [[ "$?" -eq 0 ]]; then
|
||||
DOWNLOADER="aria2c --check-certificate=false"
|
||||
else
|
||||
DOWNLOADER="wget -c"
|
||||
fi
|
||||
|
||||
echo "Remove old libs..."
|
||||
rm -rf ${PREFIX}
|
||||
rm -rf _obj
|
||||
|
||||
## Version
|
||||
OPENSSL_V=1.1.1w
|
||||
C_ARES_V=1.24.0
|
||||
ARIA2_V=1.37.0
|
||||
|
||||
## Dependencies
|
||||
OPENSSL=http://www.openssl.org/source/openssl-${OPENSSL_V}.tar.gz
|
||||
C_ARES=http://c-ares.haxx.se/download/c-ares-${C_ARES_V}.tar.gz
|
||||
ARIA2=https://github.com/aria2/aria2/releases/download/release-${ARIA2_V}/aria2-${ARIA2_V}.tar.bz2
|
||||
|
||||
## Config
|
||||
BUILD_DIRECTORY=/tmp/
|
||||
|
||||
## Build
|
||||
cd ${BUILD_DIRECTORY}
|
||||
|
||||
# c-ares build
|
||||
if ! [[ -e c&&res-${C_ARES_V}.tar.gz ]]; then
|
||||
${DOWNLOADER} ${C_ARES}
|
||||
fi
|
||||
tar zxvf c-ares-${C_ARES_V}.tar.gz
|
||||
cd c-ares-${C_ARES_V}
|
||||
PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig/ \
|
||||
LD_LIBRARY_PATH=${PREFIX}/lib/ CC="$C_COMPILER" CXX="$CXX_COMPILER" \
|
||||
./configure --prefix=${PREFIX} --enable-static --disable-shared
|
||||
make -j`nproc`
|
||||
make install
|
||||
cd ..
|
||||
|
||||
# openssl build
|
||||
if ! [[ -e openssl-${OPENSSL_V}.tar.gz ]]; then
|
||||
${DOWNLOADER} ${OPENSSL}
|
||||
fi
|
||||
tar zxvf openssl-${OPENSSL_V}.tar.gz
|
||||
cd openssl-${OPENSSL_V}
|
||||
PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig/ \
|
||||
LD_LIBRARY_PATH=${PREFIX}/lib/ CC="$C_COMPILER" CXX="$CXX_COMPILER" \
|
||||
./config --prefix=${PREFIX}
|
||||
make -j`nproc`
|
||||
make install_sw
|
||||
cd ..
|
||||
|
||||
# build aria2 static library
|
||||
if ! [[ -e aria2-${ARIA2_V}.tar.bz2 ]]; then
|
||||
${DOWNLOADER} ${ARIA2}
|
||||
fi
|
||||
tar jxvf aria2-${ARIA2_V}.tar.bz2
|
||||
cd aria2-${ARIA2_V}/
|
||||
# set specific ldflags if macOS
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
export LDFLAGS="-L${PREFIX}/lib -framework Security"
|
||||
fi
|
||||
PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig/ \
|
||||
LD_LIBRARY_PATH=${PREFIX}/lib/ \
|
||||
CC="$C_COMPILER" \
|
||||
CXX="$CXX_COMPILER" \
|
||||
./configure \
|
||||
--prefix=${PREFIX} \
|
||||
--without-sqlite3 \
|
||||
--without-libxml2 \
|
||||
--without-libexpat \
|
||||
--without-libgcrypt \
|
||||
--without-libssh2 \
|
||||
--without-libz \
|
||||
--with-openssl \
|
||||
--without-appletls \
|
||||
--without-libnettle \
|
||||
--without-gnutls \
|
||||
--without-libgmp \
|
||||
--enable-libaria2 \
|
||||
--enable-shared=no \
|
||||
--enable-static=yes
|
||||
make -j`nproc`
|
||||
make install
|
||||
cd ..
|
||||
|
||||
# cleaning
|
||||
rm -rf c-ares-${C_ARES_V}
|
||||
rm -rf openssl-${OPENSSL_V}
|
||||
rm -rf aria2-${ARIA2_V}
|
||||
rm -rf ${PREFIX}/bin
|
||||
|
||||
# generate files for c
|
||||
cd ${PREFIX}/../
|
||||
go tool cgo libaria2.go
|
||||
|
||||
echo "Prepare finished!"
|
Loading…
Add table
Add a link
Reference in a new issue