Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9d3e120f3 | ||
|
|
104df3c33c | ||
|
|
810c9d705e | ||
|
|
4ff00859a3 | ||
|
|
b77dbcc4f4 | ||
|
|
58c0aafab1 | ||
|
|
357da54083 | ||
|
|
88a7196eaf | ||
|
|
abc86a0460 | ||
|
|
dd0b7efdff | ||
|
|
7359f280b0 | ||
|
|
4eb3539347 | ||
|
|
9fb1118475 | ||
|
|
07491b43fe |
@@ -14,7 +14,7 @@ tmp_dir = "tmp"
|
|||||||
follow_symlink = false
|
follow_symlink = false
|
||||||
full_bin = ""
|
full_bin = ""
|
||||||
include_dir = []
|
include_dir = []
|
||||||
include_ext = ["go", "tpl", "tmpl", "html"]
|
include_ext = ["go", "tpl", "tmpl", "html", ".json"]
|
||||||
include_file = []
|
include_file = []
|
||||||
kill_delay = "0s"
|
kill_delay = "0s"
|
||||||
log = "build-errors.log"
|
log = "build-errors.log"
|
||||||
|
|||||||
23
.github/workflows/docker.yml
vendored
23
.github/workflows/docker.yml
vendored
@@ -12,14 +12,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Get version
|
- name: Get version
|
||||||
id: get_version
|
id: get_version
|
||||||
run: |
|
run: |
|
||||||
if [[ ${{ github.ref }} == 'refs/heads/main' ]]; then
|
LATEST_TAG=$(git tag | sort -V | tail -n1)
|
||||||
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
echo "latest_tag=${LATEST_TAG}" >> $GITHUB_ENV
|
||||||
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
@@ -42,8 +42,8 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: cy01/blackhole:beta
|
tags: cy01/blackhole:beta
|
||||||
|
|
||||||
- name: Build and push for main branch with version
|
- name: Build and push for main branch
|
||||||
if: github.ref == 'refs/heads/main' && steps.get_version.outputs.VERSION != ''
|
if: github.ref == 'refs/heads/main'
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -51,13 +51,4 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
cy01/blackhole:latest
|
cy01/blackhole:latest
|
||||||
cy01/blackhole:${{ steps.get_version.outputs.VERSION }}
|
cy01/blackhole:${{ env.latest_tag }}
|
||||||
|
|
||||||
- name: Build and push for main branch without version
|
|
||||||
if: github.ref == 'refs/heads/main' && steps.get_version.outputs.VERSION == ''
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
|
||||||
push: true
|
|
||||||
tags: cy01/blackhole:latest
|
|
||||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -91,4 +91,18 @@
|
|||||||
- Refraction of the code
|
- Refraction of the code
|
||||||
- -Fix Torbox bug
|
- -Fix Torbox bug
|
||||||
- Update CI/CD
|
- Update CI/CD
|
||||||
- Update Readme
|
- Update Readme
|
||||||
|
|
||||||
|
#### 0.3.1
|
||||||
|
|
||||||
|
- Add DebridLink Support
|
||||||
|
- Refactor error handling
|
||||||
|
|
||||||
|
#### 0.3.2
|
||||||
|
|
||||||
|
- Fix DebridLink not downloading
|
||||||
|
- Fix Torbox with uncached torrents
|
||||||
|
- Add new /internal/cached endpoint to check if an hash is cached
|
||||||
|
- implement per-debrid local cache
|
||||||
|
- Fix file check for torbox
|
||||||
|
- Other minor bug fixes
|
||||||
@@ -24,5 +24,7 @@ COPY --from=builder /app/README.md /README.md
|
|||||||
|
|
||||||
EXPOSE 8181
|
EXPOSE 8181
|
||||||
|
|
||||||
|
VOLUME ["/app"]
|
||||||
|
|
||||||
# Run
|
# Run
|
||||||
CMD ["/blackhole", "--config", "/app/config.json"]
|
CMD ["/blackhole", "--config", "/app/config.json"]
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -9,13 +9,16 @@ This is a Golang implementation go Torrent QbitTorrent with a **Real Debrid & To
|
|||||||
- Proxy support for the Arrs
|
- Proxy support for the Arrs
|
||||||
- Real Debrid Support
|
- Real Debrid Support
|
||||||
- Torbox Support
|
- Torbox Support
|
||||||
|
- Debrid Link Support
|
||||||
- Multi-Debrid Providers support
|
- Multi-Debrid Providers support
|
||||||
|
- UI for adding torrents directly to *arrs
|
||||||
|
|
||||||
The proxy is useful in filtering out un-cached Real Debrid torrents
|
The proxy is useful in filtering out un-cached Real Debrid torrents
|
||||||
|
|
||||||
### Supported Debrid Providers
|
### Supported Debrid Providers
|
||||||
- Real Debrid
|
- Real Debrid
|
||||||
- Torbox
|
- Torbox
|
||||||
|
- Debrid Link
|
||||||
|
|
||||||
### Changelog
|
### Changelog
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ Download the binary from the releases page and run it with the config file.
|
|||||||
"name": "torbox",
|
"name": "torbox",
|
||||||
"host": "https://api.torbox.app/v1",
|
"host": "https://api.torbox.app/v1",
|
||||||
"api_key": "torbox_api_key",
|
"api_key": "torbox_api_key",
|
||||||
"folder": "data/realdebrid/torrents/",
|
"folder": "data/torbox/torrents/",
|
||||||
"rate_limit": "250/minute",
|
"rate_limit": "250/minute",
|
||||||
"download_uncached": false,
|
"download_uncached": false,
|
||||||
"check_cached": true
|
"check_cached": true
|
||||||
@@ -79,6 +82,15 @@ Download the binary from the releases page and run it with the config file.
|
|||||||
"rate_limit": "250/minute",
|
"rate_limit": "250/minute",
|
||||||
"download_uncached": false,
|
"download_uncached": false,
|
||||||
"check_cached": false
|
"check_cached": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debridlink",
|
||||||
|
"host": "https://debrid-link.com/api/v2",
|
||||||
|
"api_key": "debridlink_key",
|
||||||
|
"folder": "data/debridlink/torrents/",
|
||||||
|
"rate_limit": "250/minute",
|
||||||
|
"download_uncached": false,
|
||||||
|
"check_cached": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"proxy": {
|
"proxy": {
|
||||||
@@ -163,6 +175,12 @@ Setting Up Qbittorrent in Arr
|
|||||||
- Test
|
- Test
|
||||||
- Save
|
- Save
|
||||||
|
|
||||||
|
### UI for adding torrents
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The UI is a simple web interface that allows you to add torrents directly to the Arrs(Sonarr, Radarr, etc)
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- [ ] A proper name!!!!
|
- [ ] A proper name!!!!
|
||||||
- [ ] Debrid
|
- [ ] Debrid
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ import (
|
|||||||
|
|
||||||
func Start(ctx context.Context, config *common.Config) error {
|
func Start(ctx context.Context, config *common.Config) error {
|
||||||
maxCacheSize := cmp.Or(config.MaxCacheSize, 1000)
|
maxCacheSize := cmp.Or(config.MaxCacheSize, 1000)
|
||||||
cache := common.NewCache(maxCacheSize)
|
|
||||||
|
|
||||||
deb := debrid.NewDebrid(config.Debrids, cache)
|
deb := debrid.NewDebrid(config.Debrids, maxCacheSize)
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
errChan := make(chan error, 2)
|
errChan := make(chan error, 2)
|
||||||
@@ -23,7 +22,7 @@ func Start(ctx context.Context, config *common.Config) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if err := proxy.NewProxy(*config, deb, cache).Start(ctx); err != nil {
|
if err := proxy.NewProxy(*config, deb).Start(ctx); err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -32,7 +31,7 @@ func Start(ctx context.Context, config *common.Config) error {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
if err := qbit.Start(ctx, config, deb, cache); err != nil {
|
if err := qbit.Start(ctx, config, deb); err != nil {
|
||||||
errChan <- err
|
errChan <- err
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -40,14 +40,16 @@ func (c *Cache) AddMultiple(values map[string]bool) {
|
|||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
for value := range values {
|
for value, exists := range values {
|
||||||
if _, exists := c.data[value]; !exists {
|
if !exists {
|
||||||
if len(c.order) >= c.maxItems {
|
if _, exists := c.data[value]; !exists {
|
||||||
delete(c.data, c.order[0])
|
if len(c.order) >= c.maxItems {
|
||||||
c.order = c.order[1:]
|
delete(c.data, c.order[0])
|
||||||
|
c.order = c.order[1:]
|
||||||
|
}
|
||||||
|
c.data[value] = struct{}{}
|
||||||
|
c.order = append(c.order, value)
|
||||||
}
|
}
|
||||||
c.data[value] = struct{}{}
|
|
||||||
c.order = append(c.order, value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ func (c *RLHTTPClient) MakeRequest(req *http.Request) ([]byte, error) {
|
|||||||
b, _ := io.ReadAll(res.Body)
|
b, _ := io.ReadAll(res.Body)
|
||||||
statusOk := strconv.Itoa(res.StatusCode)[0] == '2'
|
statusOk := strconv.Itoa(res.StatusCode)[0] == '2'
|
||||||
if !statusOk {
|
if !statusOk {
|
||||||
return nil, fmt.Errorf("unexpected status code: %d", res.StatusCode)
|
// Add status code error to the body
|
||||||
|
b = append(b, []byte(fmt.Sprintf("\nstatus code: %d", res.StatusCode))...)
|
||||||
|
return nil, fmt.Errorf(string(b))
|
||||||
}
|
}
|
||||||
defer func(Body io.ReadCloser) {
|
defer func(Body io.ReadCloser) {
|
||||||
err := Body.Close()
|
err := Body.Close()
|
||||||
|
|||||||
BIN
doc/ui.png
Normal file
BIN
doc/ui.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
@@ -34,10 +34,13 @@ type Service interface {
|
|||||||
GetLogger() *log.Logger
|
GetLogger() *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDebrid(debs []common.DebridConfig, cache *common.Cache) *DebridService {
|
func NewDebrid(debs []common.DebridConfig, maxCachedSize int) *DebridService {
|
||||||
debrids := make([]Service, 0)
|
debrids := make([]Service, 0)
|
||||||
|
// Divide the cache size by the number of debrids
|
||||||
|
maxCacheSize := maxCachedSize / len(debs)
|
||||||
|
|
||||||
for _, dc := range debs {
|
for _, dc := range debs {
|
||||||
d := createDebrid(dc, cache)
|
d := createDebrid(dc, common.NewCache(maxCacheSize))
|
||||||
d.GetLogger().Println("Debrid Service started")
|
d.GetLogger().Println("Debrid Service started")
|
||||||
debrids = append(debrids, d)
|
debrids = append(debrids, d)
|
||||||
}
|
}
|
||||||
@@ -114,26 +117,27 @@ func getTorrentInfo(filePath string) (*Torrent, error) {
|
|||||||
|
|
||||||
func GetLocalCache(infohashes []string, cache *common.Cache) ([]string, map[string]bool) {
|
func GetLocalCache(infohashes []string, cache *common.Cache) ([]string, map[string]bool) {
|
||||||
result := make(map[string]bool)
|
result := make(map[string]bool)
|
||||||
|
hashes := make([]string, 0)
|
||||||
|
|
||||||
//if len(infohashes) == 0 {
|
if len(infohashes) == 0 {
|
||||||
// return hashes, result
|
return hashes, result
|
||||||
//}
|
}
|
||||||
//if len(infohashes) == 1 {
|
if len(infohashes) == 1 {
|
||||||
// if cache.Exists(infohashes[0]) {
|
if cache.Exists(infohashes[0]) {
|
||||||
// return hashes, map[string]bool{infohashes[0]: true}
|
return hashes, map[string]bool{infohashes[0]: true}
|
||||||
// }
|
}
|
||||||
// return infohashes, result
|
return infohashes, result
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//cachedHashes := cache.GetMultiple(infohashes)
|
cachedHashes := cache.GetMultiple(infohashes)
|
||||||
//for _, h := range infohashes {
|
for _, h := range infohashes {
|
||||||
// _, exists := cachedHashes[h]
|
_, exists := cachedHashes[h]
|
||||||
// if !exists {
|
if !exists {
|
||||||
// hashes = append(hashes, h)
|
hashes = append(hashes, h)
|
||||||
// } else {
|
} else {
|
||||||
// result[h] = true
|
result[h] = true
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
return infohashes, result
|
return infohashes, result
|
||||||
}
|
}
|
||||||
@@ -147,6 +151,8 @@ func ProcessTorrent(d *DebridService, magnet *common.Magnet, a *arr.Arr, isSymli
|
|||||||
Size: magnet.Size,
|
Size: magnet.Size,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errs := make([]error, 0)
|
||||||
|
|
||||||
for index, db := range d.debrids {
|
for index, db := range d.debrids {
|
||||||
log.Println("Processing debrid: ", db.GetName())
|
log.Println("Processing debrid: ", db.GetName())
|
||||||
logger := db.GetLogger()
|
logger := db.GetLogger()
|
||||||
@@ -162,15 +168,21 @@ func ProcessTorrent(d *DebridService, magnet *common.Magnet, a *arr.Arr, isSymli
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbt, err := db.SubmitMagnet(debridTorrent)
|
dbt, err := db.SubmitMagnet(debridTorrent)
|
||||||
if err != nil || dbt.Id == "" {
|
if dbt != nil {
|
||||||
logger.Printf("Error submitting magnet: %s", err)
|
dbt.Debrid = db
|
||||||
|
dbt.Arr = a
|
||||||
|
}
|
||||||
|
if err != nil || dbt == nil || dbt.Id == "" {
|
||||||
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logger.Printf("Torrent: %s submitted to %s", dbt.Name, db.GetName())
|
logger.Printf("Torrent: %s submitted to %s", dbt.Name, db.GetName())
|
||||||
d.lastUsed = index
|
d.lastUsed = index
|
||||||
dbt.Debrid = db
|
|
||||||
dbt.Arr = a
|
|
||||||
return db.CheckStatus(dbt, isSymlink)
|
return db.CheckStatus(dbt, isSymlink)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("failed to process torrent")
|
err := fmt.Errorf("failed to process torrent")
|
||||||
|
for _, e := range errs {
|
||||||
|
err = fmt.Errorf("%w\n%w", err, e)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ func (r *DebridLink) IsAvailable(infohashes []string) map[string]bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Divide hashes into groups of 100
|
// Divide hashes into groups of 100
|
||||||
for i := 0; i < len(hashes); i += 200 {
|
for i := 0; i < len(hashes); i += 100 {
|
||||||
end := i + 200
|
end := i + 100
|
||||||
if end > len(hashes) {
|
if end > len(hashes) {
|
||||||
end = len(hashes)
|
end = len(hashes)
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ func (r *DebridLink) IsAvailable(infohashes []string) map[string]bool {
|
|||||||
|
|
||||||
func (r *DebridLink) GetTorrent(id string) (*Torrent, error) {
|
func (r *DebridLink) GetTorrent(id string) (*Torrent, error) {
|
||||||
torrent := &Torrent{}
|
torrent := &Torrent{}
|
||||||
url := fmt.Sprintf("%s/seedbox/list/?ids=%s", r.Host, id)
|
url := fmt.Sprintf("%s/seedbox/list?ids=%s", r.Host, id)
|
||||||
req, _ := http.NewRequest(http.MethodGet, url, nil)
|
req, _ := http.NewRequest(http.MethodGet, url, nil)
|
||||||
resp, err := r.client.MakeRequest(req)
|
resp, err := r.client.MakeRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -113,6 +113,9 @@ func (r *DebridLink) GetTorrent(id string) (*Torrent, error) {
|
|||||||
}
|
}
|
||||||
data := dt[0]
|
data := dt[0]
|
||||||
status := "downloading"
|
status := "downloading"
|
||||||
|
if data.Status == 100 {
|
||||||
|
status = "downloaded"
|
||||||
|
}
|
||||||
name := common.RemoveInvalidChars(data.Name)
|
name := common.RemoveInvalidChars(data.Name)
|
||||||
torrent.Id = data.ID
|
torrent.Id = data.ID
|
||||||
torrent.Name = name
|
torrent.Name = name
|
||||||
@@ -185,8 +188,8 @@ func (r *DebridLink) SubmitMagnet(torrent *Torrent) (*Torrent, error) {
|
|||||||
|
|
||||||
func (r *DebridLink) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, error) {
|
func (r *DebridLink) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, error) {
|
||||||
for {
|
for {
|
||||||
torrent, err := r.GetTorrent(torrent.Id)
|
t, err := r.GetTorrent(torrent.Id)
|
||||||
|
torrent = t
|
||||||
if err != nil || torrent == nil {
|
if err != nil || torrent == nil {
|
||||||
return torrent, err
|
return torrent, err
|
||||||
}
|
}
|
||||||
@@ -248,6 +251,7 @@ func NewDebridLink(dc common.DebridConfig, cache *common.Cache) *DebridLink {
|
|||||||
rl := common.ParseRateLimit(dc.RateLimit)
|
rl := common.ParseRateLimit(dc.RateLimit)
|
||||||
headers := map[string]string{
|
headers := map[string]string{
|
||||||
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
||||||
|
"Content-Type": "application/json",
|
||||||
}
|
}
|
||||||
client := common.NewRLHTTPClient(rl, headers)
|
client := common.NewRLHTTPClient(rl, headers)
|
||||||
logger := common.NewLogger(dc.Name, os.Stdout)
|
logger := common.NewLogger(dc.Name, os.Stdout)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
gourl "net/url"
|
gourl "net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -179,13 +180,13 @@ func (r *RealDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
|
|||||||
torrent.Links = data.Links
|
torrent.Links = data.Links
|
||||||
torrent.Status = status
|
torrent.Status = status
|
||||||
torrent.Debrid = r
|
torrent.Debrid = r
|
||||||
|
downloadingStatus := []string{"downloading", "magnet_conversion", "queued", "compressing", "uploading"}
|
||||||
if status == "error" || status == "dead" || status == "magnet_error" {
|
if status == "error" || status == "dead" || status == "magnet_error" {
|
||||||
return torrent, fmt.Errorf("torrent: %s has error", torrent.Name)
|
return torrent, fmt.Errorf("torrent: %s has error: %s", torrent.Name, status)
|
||||||
} else if status == "waiting_files_selection" {
|
} else if status == "waiting_files_selection" {
|
||||||
files := GetTorrentFiles(data)
|
files := GetTorrentFiles(data)
|
||||||
torrent.Files = files
|
torrent.Files = files
|
||||||
if len(files) == 0 {
|
if len(files) == 0 {
|
||||||
go torrent.Delete()
|
|
||||||
return torrent, fmt.Errorf("no video files found")
|
return torrent, fmt.Errorf("no video files found")
|
||||||
}
|
}
|
||||||
filesId := make([]string, 0)
|
filesId := make([]string, 0)
|
||||||
@@ -212,9 +213,8 @@ func (r *RealDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
} else if status == "downloading" {
|
} else if slices.Contains(downloadingStatus, status) {
|
||||||
if !r.DownloadUncached {
|
if !r.DownloadUncached {
|
||||||
go torrent.Delete()
|
|
||||||
return torrent, fmt.Errorf("torrent: %s not cached", torrent.Name)
|
return torrent, fmt.Errorf("torrent: %s not cached", torrent.Name)
|
||||||
}
|
}
|
||||||
// Break out of the loop if the torrent is downloading.
|
// Break out of the loop if the torrent is downloading.
|
||||||
|
|||||||
@@ -11,3 +11,12 @@ func (d *DebridService) Get() Service {
|
|||||||
}
|
}
|
||||||
return d.debrids[d.lastUsed]
|
return d.debrids[d.lastUsed]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DebridService) GetByName(name string) Service {
|
||||||
|
for _, deb := range d.debrids {
|
||||||
|
if deb.GetName() == name {
|
||||||
|
return deb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ type torboxInfo struct {
|
|||||||
DownloadState string `json:"download_state"`
|
DownloadState string `json:"download_state"`
|
||||||
Seeds int `json:"seeds"`
|
Seeds int `json:"seeds"`
|
||||||
Peers int `json:"peers"`
|
Peers int `json:"peers"`
|
||||||
Ratio int `json:"ratio"`
|
Ratio float64 `json:"ratio"`
|
||||||
Progress float64 `json:"progress"`
|
Progress float64 `json:"progress"`
|
||||||
DownloadSpeed int `json:"download_speed"`
|
DownloadSpeed int `json:"download_speed"`
|
||||||
UploadSpeed int `json:"upload_speed"`
|
UploadSpeed int `json:"upload_speed"`
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ func (r *Torbox) IsAvailable(infohashes []string) map[string]bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Divide hashes into groups of 100
|
// Divide hashes into groups of 100
|
||||||
for i := 0; i < len(hashes); i += 200 {
|
for i := 0; i < len(hashes); i += 100 {
|
||||||
end := i + 200
|
end := i + 100
|
||||||
if end > len(hashes) {
|
if end > len(hashes) {
|
||||||
end = len(hashes)
|
end = len(hashes)
|
||||||
}
|
}
|
||||||
@@ -165,9 +165,6 @@ func (r *Torbox) GetTorrent(id string) (*Torrent, error) {
|
|||||||
torrent.Filename = name
|
torrent.Filename = name
|
||||||
torrent.OriginalFilename = name
|
torrent.OriginalFilename = name
|
||||||
files := make([]TorrentFile, 0)
|
files := make([]TorrentFile, 0)
|
||||||
if len(data.Files) == 0 {
|
|
||||||
return torrent, fmt.Errorf("no files found for torrent: %s", name)
|
|
||||||
}
|
|
||||||
for _, f := range data.Files {
|
for _, f := range data.Files {
|
||||||
fileName := filepath.Base(f.Name)
|
fileName := filepath.Base(f.Name)
|
||||||
if (!common.RegexMatch(common.VIDEOMATCH, fileName) &&
|
if (!common.RegexMatch(common.VIDEOMATCH, fileName) &&
|
||||||
@@ -183,10 +180,13 @@ func (r *Torbox) GetTorrent(id string) (*Torrent, error) {
|
|||||||
}
|
}
|
||||||
files = append(files, file)
|
files = append(files, file)
|
||||||
}
|
}
|
||||||
if len(files) == 0 {
|
var cleanPath string
|
||||||
return torrent, fmt.Errorf("no video files found")
|
if len(files) > 0 {
|
||||||
|
cleanPath = path.Clean(data.Files[0].Name)
|
||||||
|
} else {
|
||||||
|
cleanPath = path.Clean(data.Name)
|
||||||
}
|
}
|
||||||
cleanPath := path.Clean(data.Files[0].Name)
|
|
||||||
torrent.OriginalFilename = strings.Split(cleanPath, "/")[0]
|
torrent.OriginalFilename = strings.Split(cleanPath, "/")[0]
|
||||||
torrent.Files = files
|
torrent.Files = files
|
||||||
torrent.Debrid = r
|
torrent.Debrid = r
|
||||||
@@ -229,7 +229,7 @@ func (r *Torbox) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Torbox) DeleteTorrent(torrent *Torrent) {
|
func (r *Torbox) DeleteTorrent(torrent *Torrent) {
|
||||||
url := fmt.Sprintf("%s/api//torrents/controltorrent/%s", r.Host, torrent.Id)
|
url := fmt.Sprintf("%s/api/torrents/controltorrent/%s", r.Host, torrent.Id)
|
||||||
payload := map[string]string{"torrent_id": torrent.Id, "action": "Delete"}
|
payload := map[string]string{"torrent_id": torrent.Id, "action": "Delete"}
|
||||||
jsonPayload, _ := json.Marshal(payload)
|
jsonPayload, _ := json.Marshal(payload)
|
||||||
req, _ := http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(jsonPayload))
|
req, _ := http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(jsonPayload))
|
||||||
|
|||||||
@@ -74,7 +74,11 @@ func (t *Torrent) GetMountFolder(rClonePath string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) Delete() {
|
func (t *Torrent) Delete() {
|
||||||
|
if t.Debrid == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
t.Debrid.DeleteTorrent(t)
|
t.Debrid.DeleteTorrent(t)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TorrentFile struct {
|
type TorrentFile struct {
|
||||||
|
|||||||
@@ -75,11 +75,10 @@ type Proxy struct {
|
|||||||
password string
|
password string
|
||||||
cachedOnly bool
|
cachedOnly bool
|
||||||
debrid debrid.Service
|
debrid debrid.Service
|
||||||
cache *common.Cache
|
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy(config common.Config, deb *debrid.DebridService, cache *common.Cache) *Proxy {
|
func NewProxy(config common.Config, deb *debrid.DebridService) *Proxy {
|
||||||
cfg := config.Proxy
|
cfg := config.Proxy
|
||||||
port := cmp.Or(os.Getenv("PORT"), cfg.Port, "8181")
|
port := cmp.Or(os.Getenv("PORT"), cfg.Port, "8181")
|
||||||
return &Proxy{
|
return &Proxy{
|
||||||
@@ -90,7 +89,6 @@ func NewProxy(config common.Config, deb *debrid.DebridService, cache *common.Cac
|
|||||||
password: cfg.Password,
|
password: cfg.Password,
|
||||||
cachedOnly: *cfg.CachedOnly,
|
cachedOnly: *cfg.CachedOnly,
|
||||||
debrid: deb.Get(),
|
debrid: deb.Get(),
|
||||||
cache: cache,
|
|
||||||
logger: common.NewLogger("Proxy", os.Stdout),
|
logger: common.NewLogger("Proxy", os.Stdout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"goBlack/pkg/qbit/server"
|
"goBlack/pkg/qbit/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Start(ctx context.Context, config *common.Config, deb *debrid.DebridService, cache *common.Cache) error {
|
func Start(ctx context.Context, config *common.Config, deb *debrid.DebridService) error {
|
||||||
srv := server.NewServer(config, deb, cache)
|
srv := server.NewServer(config, deb)
|
||||||
if err := srv.Start(ctx); err != nil {
|
if err := srv.Start(ctx); err != nil {
|
||||||
return fmt.Errorf("failed to start qbit server: %w", err)
|
return fmt.Errorf("failed to start qbit server: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,9 @@ func (i *ImportRequest) Process(s *Server) (err error) {
|
|||||||
torrent := q.CreateTorrentFromMagnet(magnet, i.Arr.Name)
|
torrent := q.CreateTorrentFromMagnet(magnet, i.Arr.Name)
|
||||||
debridTorrent, err := debrid.ProcessTorrent(q.Debrid, magnet, i.Arr, i.IsSymlink)
|
debridTorrent, err := debrid.ProcessTorrent(q.Debrid, magnet, i.Arr, i.IsSymlink)
|
||||||
if err != nil || debridTorrent == nil {
|
if err != nil || debridTorrent == nil {
|
||||||
|
if debridTorrent != nil {
|
||||||
|
go debridTorrent.Delete()
|
||||||
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = fmt.Errorf("failed to process torrent")
|
err = fmt.Errorf("failed to process torrent")
|
||||||
}
|
}
|
||||||
@@ -95,8 +98,11 @@ func (i *ImportRequest) BetaProcess(s *Server) (err error) {
|
|||||||
}
|
}
|
||||||
debridTorrent, err := debrid.ProcessTorrent(q.Debrid, magnet, i.Arr, true)
|
debridTorrent, err := debrid.ProcessTorrent(q.Debrid, magnet, i.Arr, true)
|
||||||
if err != nil || debridTorrent == nil {
|
if err != nil || debridTorrent == nil {
|
||||||
|
if debridTorrent != nil {
|
||||||
|
go debridTorrent.Delete()
|
||||||
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = errors.New("failed to process torrent")
|
err = fmt.Errorf("failed to process torrent")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ func (s *Server) Routes(r chi.Router) http.Handler {
|
|||||||
r.Get("/episodes/{contentId}", s.handleEpisodes)
|
r.Get("/episodes/{contentId}", s.handleEpisodes)
|
||||||
r.Post("/add", s.handleAddContent)
|
r.Post("/add", s.handleAddContent)
|
||||||
r.Get("/search", s.handleSearch)
|
r.Get("/search", s.handleSearch)
|
||||||
|
r.Get("/cached", s.handleCheckCached)
|
||||||
})
|
})
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ type Server struct {
|
|||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(config *common.Config, deb *debrid.DebridService, cache *common.Cache) *Server {
|
func NewServer(config *common.Config, deb *debrid.DebridService) *Server {
|
||||||
logger := common.NewLogger("QBit", os.Stdout)
|
logger := common.NewLogger("QBit", os.Stdout)
|
||||||
q := shared.NewQBit(config, deb, cache, logger)
|
q := shared.NewQBit(config, deb, logger)
|
||||||
return &Server{
|
return &Server{
|
||||||
qbit: q,
|
qbit: q,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ func (s *Server) handleTorrentsAdd(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, "isSymlink", isSymlink)
|
ctx = context.WithValue(ctx, "isSymlink", isSymlink)
|
||||||
|
|
||||||
for _, url := range urlList {
|
for _, url := range urlList {
|
||||||
if err := s.qbit.AddMagnet(ctx, url, category); err != nil {
|
if err := s.qbit.AddMagnet(ctx, url, category); err != nil {
|
||||||
s.logger.Printf("Error adding magnet: %v\n", err)
|
s.logger.Printf("Error adding magnet: %v\n", err)
|
||||||
@@ -59,7 +58,7 @@ func (s *Server) handleTorrentsAdd(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if contentType == "multipart/form-data" {
|
if contentType == "multipart/form-data" && len(r.MultipartForm.File["torrents"]) > 0 {
|
||||||
files := r.MultipartForm.File["torrents"]
|
files := r.MultipartForm.File["torrents"]
|
||||||
for _, fileHeader := range files {
|
for _, fileHeader := range files {
|
||||||
if err := s.qbit.AddTorrent(ctx, fileHeader, category); err != nil {
|
if err := s.qbit.AddTorrent(ctx, fileHeader, category); err != nil {
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"goBlack/common"
|
"goBlack/common"
|
||||||
"goBlack/pkg/arr"
|
"goBlack/pkg/arr"
|
||||||
|
"goBlack/pkg/debrid"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AddRequest struct {
|
type AddRequest struct {
|
||||||
@@ -112,3 +114,36 @@ func (s *Server) handleAddContent(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
common.JSONResponse(w, importReq, http.StatusOK)
|
common.JSONResponse(w, importReq, http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleCheckCached(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_hashes := r.URL.Query().Get("hash")
|
||||||
|
if _hashes == "" {
|
||||||
|
http.Error(w, "No hashes provided", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
hashes := strings.Split(_hashes, ",")
|
||||||
|
if len(hashes) == 0 {
|
||||||
|
http.Error(w, "No hashes provided", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
db := r.URL.Query().Get("debrid")
|
||||||
|
var deb debrid.Service
|
||||||
|
if db == "" {
|
||||||
|
// use the first debrid
|
||||||
|
deb = s.qbit.Debrid.Get()
|
||||||
|
} else {
|
||||||
|
deb = s.qbit.Debrid.GetByName(db)
|
||||||
|
}
|
||||||
|
if deb == nil {
|
||||||
|
http.Error(w, "Invalid debrid", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res := deb.IsAvailable(hashes)
|
||||||
|
result := make(map[string]bool)
|
||||||
|
for _, h := range hashes {
|
||||||
|
_, exists := res[h]
|
||||||
|
result[h] = exists
|
||||||
|
}
|
||||||
|
common.JSONResponse(w, result, http.StatusOK)
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ type QBit struct {
|
|||||||
DownloadFolder string `json:"download_folder"`
|
DownloadFolder string `json:"download_folder"`
|
||||||
Categories []string `json:"categories"`
|
Categories []string `json:"categories"`
|
||||||
Debrid *debrid.DebridService
|
Debrid *debrid.DebridService
|
||||||
cache *common.Cache
|
|
||||||
Storage *TorrentStorage
|
Storage *TorrentStorage
|
||||||
debug bool
|
debug bool
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
@@ -24,7 +23,7 @@ type QBit struct {
|
|||||||
RefreshInterval int
|
RefreshInterval int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewQBit(config *common.Config, deb *debrid.DebridService, cache *common.Cache, logger *log.Logger) *QBit {
|
func NewQBit(config *common.Config, deb *debrid.DebridService, logger *log.Logger) *QBit {
|
||||||
cfg := config.QBitTorrent
|
cfg := config.QBitTorrent
|
||||||
port := cmp.Or(cfg.Port, os.Getenv("QBIT_PORT"), "8182")
|
port := cmp.Or(cfg.Port, os.Getenv("QBIT_PORT"), "8182")
|
||||||
refreshInterval := cmp.Or(cfg.RefreshInterval, 10)
|
refreshInterval := cmp.Or(cfg.RefreshInterval, 10)
|
||||||
@@ -36,7 +35,6 @@ func NewQBit(config *common.Config, deb *debrid.DebridService, cache *common.Cac
|
|||||||
DownloadFolder: cfg.DownloadFolder,
|
DownloadFolder: cfg.DownloadFolder,
|
||||||
Categories: cfg.Categories,
|
Categories: cfg.Categories,
|
||||||
Debrid: deb,
|
Debrid: deb,
|
||||||
cache: cache,
|
|
||||||
debug: cfg.Debug,
|
debug: cfg.Debug,
|
||||||
Storage: NewTorrentStorage("torrents.json"),
|
Storage: NewTorrentStorage("torrents.json"),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type TorrentStorage struct {
|
|||||||
torrents map[string]*Torrent
|
torrents map[string]*Torrent
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
order []string
|
order []string
|
||||||
|
filename string // Added to store the filename for persistence
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadTorrentsFromJSON(filename string) (map[string]*Torrent, error) {
|
func loadTorrentsFromJSON(filename string) (map[string]*Torrent, error) {
|
||||||
@@ -25,7 +26,7 @@ func loadTorrentsFromJSON(filename string) (map[string]*Torrent, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTorrentStorage(filename string) *TorrentStorage {
|
func NewTorrentStorage(filename string) *TorrentStorage {
|
||||||
// Open the json file and read the data
|
// Open the JSON file and read the data
|
||||||
torrents, err := loadTorrentsFromJSON(filename)
|
torrents, err := loadTorrentsFromJSON(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
torrents = make(map[string]*Torrent)
|
torrents = make(map[string]*Torrent)
|
||||||
@@ -38,6 +39,7 @@ func NewTorrentStorage(filename string) *TorrentStorage {
|
|||||||
return &TorrentStorage{
|
return &TorrentStorage{
|
||||||
torrents: torrents,
|
torrents: torrents,
|
||||||
order: order,
|
order: order,
|
||||||
|
filename: filename,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ func (ts *TorrentStorage) Add(torrent *Torrent) {
|
|||||||
defer ts.mu.Unlock()
|
defer ts.mu.Unlock()
|
||||||
ts.torrents[torrent.Hash] = torrent
|
ts.torrents[torrent.Hash] = torrent
|
||||||
ts.order = append(ts.order, torrent.Hash)
|
ts.order = append(ts.order, torrent.Hash)
|
||||||
|
_ = ts.saveToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TorrentStorage) AddOrUpdate(torrent *Torrent) {
|
func (ts *TorrentStorage) AddOrUpdate(torrent *Torrent) {
|
||||||
@@ -55,6 +58,7 @@ func (ts *TorrentStorage) AddOrUpdate(torrent *Torrent) {
|
|||||||
ts.order = append(ts.order, torrent.Hash)
|
ts.order = append(ts.order, torrent.Hash)
|
||||||
}
|
}
|
||||||
ts.torrents[torrent.Hash] = torrent
|
ts.torrents[torrent.Hash] = torrent
|
||||||
|
_ = ts.saveToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TorrentStorage) GetByID(id string) *Torrent {
|
func (ts *TorrentStorage) GetByID(id string) *Torrent {
|
||||||
@@ -104,6 +108,7 @@ func (ts *TorrentStorage) Update(torrent *Torrent) {
|
|||||||
ts.mu.Lock()
|
ts.mu.Lock()
|
||||||
defer ts.mu.Unlock()
|
defer ts.mu.Unlock()
|
||||||
ts.torrents[torrent.Hash] = torrent
|
ts.torrents[torrent.Hash] = torrent
|
||||||
|
_ = ts.saveToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TorrentStorage) Delete(hash string) {
|
func (ts *TorrentStorage) Delete(hash string) {
|
||||||
@@ -127,14 +132,20 @@ func (ts *TorrentStorage) Delete(hash string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ = ts.saveToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ts *TorrentStorage) Save(filename string) error {
|
func (ts *TorrentStorage) Save() error {
|
||||||
ts.mu.RLock()
|
ts.mu.RLock()
|
||||||
defer ts.mu.RUnlock()
|
defer ts.mu.RUnlock()
|
||||||
data, err := json.Marshal(ts.torrents)
|
return ts.saveToFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveToFile is a helper function to write the current state to the JSON file
|
||||||
|
func (ts *TorrentStorage) saveToFile() error {
|
||||||
|
data, err := json.MarshalIndent(ts.torrents, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.WriteFile(filename, data, 0644)
|
return os.WriteFile(ts.filename, data, 0644)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,11 @@ import (
|
|||||||
func (q *QBit) AddMagnet(ctx context.Context, url, category string) error {
|
func (q *QBit) AddMagnet(ctx context.Context, url, category string) error {
|
||||||
magnet, err := common.GetMagnetFromUrl(url)
|
magnet, err := common.GetMagnetFromUrl(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Error parsing magnet link: %v\n", err)
|
return fmt.Errorf("error parsing magnet link: %w", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
err = q.Process(ctx, magnet, category)
|
err = q.Process(ctx, magnet, category)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Println("Failed to process magnet:", err)
|
return fmt.Errorf("failed to process torrent: %w", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -38,13 +36,11 @@ func (q *QBit) AddTorrent(ctx context.Context, fileHeader *multipart.FileHeader,
|
|||||||
var reader io.Reader = file
|
var reader io.Reader = file
|
||||||
magnet, err := common.GetMagnetFromFile(reader, fileHeader.Filename)
|
magnet, err := common.GetMagnetFromFile(reader, fileHeader.Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Error reading file: %s", fileHeader.Filename)
|
return fmt.Errorf("error reading file: %s \n %w", fileHeader.Filename, err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
err = q.Process(ctx, magnet, category)
|
err = q.Process(ctx, magnet, category)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Println("Failed to process torrent:", err)
|
return fmt.Errorf("failed to process torrent: %w", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -58,6 +54,9 @@ func (q *QBit) Process(ctx context.Context, magnet *common.Magnet, category stri
|
|||||||
isSymlink := ctx.Value("isSymlink").(bool)
|
isSymlink := ctx.Value("isSymlink").(bool)
|
||||||
debridTorrent, err := debrid.ProcessTorrent(q.Debrid, magnet, a, isSymlink)
|
debridTorrent, err := debrid.ProcessTorrent(q.Debrid, magnet, a, isSymlink)
|
||||||
if err != nil || debridTorrent == nil {
|
if err != nil || debridTorrent == nil {
|
||||||
|
if debridTorrent != nil {
|
||||||
|
go debridTorrent.Delete()
|
||||||
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = fmt.Errorf("failed to process torrent")
|
err = fmt.Errorf("failed to process torrent")
|
||||||
}
|
}
|
||||||
@@ -93,10 +92,11 @@ func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr
|
|||||||
for debridTorrent.Status != "downloaded" {
|
for debridTorrent.Status != "downloaded" {
|
||||||
progress := debridTorrent.Progress
|
progress := debridTorrent.Progress
|
||||||
q.logger.Printf("%s Download Progress: %.2f%%", debridTorrent.Debrid.GetName(), progress)
|
q.logger.Printf("%s Download Progress: %.2f%%", debridTorrent.Debrid.GetName(), progress)
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(4 * time.Second)
|
||||||
dbT, err := debridTorrent.Debrid.CheckStatus(debridTorrent, isSymlink)
|
dbT, err := debridTorrent.Debrid.CheckStatus(debridTorrent, isSymlink)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Error checking status: %v", err)
|
q.logger.Printf("Error checking status: %v", err)
|
||||||
|
go debridTorrent.Delete()
|
||||||
q.MarkAsFailed(torrent)
|
q.MarkAsFailed(torrent)
|
||||||
_ = arr.Refresh()
|
_ = arr.Refresh()
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user