Changelog v0.4.0
This commit is contained in:
+10
-2
@@ -39,7 +39,7 @@
|
|||||||
- Rewrote the whole codebase
|
- Rewrote the whole codebase
|
||||||
|
|
||||||
|
|
||||||
#### 0.2.0
|
### 0.2.0
|
||||||
- Implement 0.2.0-beta changes
|
- Implement 0.2.0-beta changes
|
||||||
- Removed Blackhole
|
- Removed Blackhole
|
||||||
- Added QbitTorrent API
|
- Added QbitTorrent API
|
||||||
@@ -107,9 +107,17 @@
|
|||||||
- Fix file check for torbox
|
- Fix file check for torbox
|
||||||
- Other minor bug fixes
|
- Other minor bug fixes
|
||||||
|
|
||||||
|
|
||||||
#### 0.3.3
|
#### 0.3.3
|
||||||
|
|
||||||
- Add AllDebrid Support
|
- Add AllDebrid Support
|
||||||
- Fix Torbox not downloading uncached torrents
|
- Fix Torbox not downloading uncached torrents
|
||||||
- Fix Rar files being downloaded
|
- Fix Rar files being downloaded
|
||||||
|
|
||||||
|
#### 0.4.0
|
||||||
|
|
||||||
|
- Add support for multiple debrid providers
|
||||||
|
- A full-fledged UI for adding torrents, repairing files, viewing config and managing torrents
|
||||||
|
- Add a more robust logging system
|
||||||
|
- Fix issues with Alldebrid
|
||||||
|
- Fix file transversal bug
|
||||||
|
- Fix files with no parent directory
|
||||||
@@ -1,30 +1,28 @@
|
|||||||
### GoBlackHole(with Debrid Proxy Support)
|
### DecyphArr(with Debrid Proxy Support)
|
||||||
|
|
||||||
This is a Golang implementation go Torrent QbitTorrent with a **Real Debrid & Torbox Support**.
|

|
||||||
|
|
||||||
|
This is a Golang implementation go Torrent QbitTorrent with a **Multiple Debrid service support**.
|
||||||
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- Mock Qbittorent API that supports the Arrs(Sonarr, Radarr, etc)
|
- Mock Qbittorent API that supports the Arrs(Sonarr, Radarr, etc)
|
||||||
|
- A Full-fledged UI for managing torrents
|
||||||
- Proxy support for the Arrs
|
- Proxy support for the Arrs
|
||||||
- Real Debrid Support
|
- Real Debrid Support
|
||||||
- Torbox Support
|
- Torbox Support
|
||||||
- Debrid Link Support
|
- Debrid Link Support
|
||||||
- Multi-Debrid Providers support
|
- Multi-Debrid Providers support
|
||||||
- UI for adding torrents directly to *arrs
|
|
||||||
- Repair Worker for missing files (**NEW**)
|
- Repair Worker for missing files (**NEW**)
|
||||||
|
|
||||||
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](https://real-debrid.com)
|
||||||
- Torbox
|
- [Torbox](https://torbox.app)
|
||||||
- Debrid Link
|
- [Debrid Link](https://debrid-link.com)
|
||||||
- All Debrid
|
- [All Debrid](https://alldebrid.com)
|
||||||
|
|
||||||
### Changelog
|
|
||||||
|
|
||||||
- View the [CHANGELOG.md](CHANGELOG.md) for the latest changes
|
|
||||||
|
|
||||||
|
|
||||||
#### Installation
|
#### Installation
|
||||||
@@ -63,7 +61,28 @@ Download the binary from the releases page and run it with the config file.
|
|||||||
./blackhole --config /path/to/config.json
|
./blackhole --config /path/to/config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Config
|
### Usage
|
||||||
|
- The UI is available at `http://localhost:8282`
|
||||||
|
- Setup the config.json file. Scroll down for the sample config file
|
||||||
|
- Setup docker compose/ binary with the config file
|
||||||
|
- Start the service
|
||||||
|
- Connect to Sonarr/Radarr/Lidarr
|
||||||
|
|
||||||
|
#### Connecting to Sonarr/Radarr
|
||||||
|
|
||||||
|
- Sonarr/Radarr
|
||||||
|
- Settings -> Download Client -> Add Client -> qBittorrent
|
||||||
|
- Host: `localhost` # or the IP of the server
|
||||||
|
- Port: `8282` # or the port set in the config file/ docker-compose env
|
||||||
|
- Username: `http://sonarr:8989` # Your arr host with http/https
|
||||||
|
- Password: `sonarr_token` # Your arr token
|
||||||
|
- Category: e.g `sonarr`, `radarr`
|
||||||
|
- Use SSL -> `No`
|
||||||
|
- Sequential Download -> `No`|`Yes` (If you want to download the torrents locally instead of symlink)
|
||||||
|
- Test
|
||||||
|
- Save
|
||||||
|
|
||||||
|
#### Sample Config
|
||||||
|
|
||||||
This is the default config file. You can create a `config.json` file in the root directory of the project or mount it in the docker-compose file.
|
This is the default config file. You can create a `config.json` file in the root directory of the project or mount it in the docker-compose file.
|
||||||
```json
|
```json
|
||||||
@@ -109,7 +128,7 @@ This is the default config file. You can create a `config.json` file in the root
|
|||||||
"proxy": {
|
"proxy": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"port": "8100",
|
"port": "8100",
|
||||||
"debug": false,
|
"log_level": "info",
|
||||||
"username": "username",
|
"username": "username",
|
||||||
"password": "password",
|
"password": "password",
|
||||||
"cached_only": true
|
"cached_only": true
|
||||||
@@ -119,7 +138,8 @@ This is the default config file. You can create a `config.json` file in the root
|
|||||||
"port": "8282",
|
"port": "8282",
|
||||||
"download_folder": "/media/symlinks/",
|
"download_folder": "/media/symlinks/",
|
||||||
"categories": ["sonarr", "radarr"],
|
"categories": ["sonarr", "radarr"],
|
||||||
"refresh_interval": 5
|
"refresh_interval": 5,
|
||||||
|
"log_level": "info"
|
||||||
},
|
},
|
||||||
"arrs": [
|
"arrs": [
|
||||||
{
|
{
|
||||||
@@ -132,11 +152,21 @@ This is the default config file. You can create a `config.json` file in the root
|
|||||||
"host": "http://host:7878",
|
"host": "http://host:7878",
|
||||||
"token": "arr_key"
|
"token": "arr_key"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"repair": {
|
||||||
|
"enabled": true,
|
||||||
|
"interval": "12h",
|
||||||
|
"run_on_start": false
|
||||||
|
},
|
||||||
|
"log_level": "info"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Config Notes
|
#### Config Notes
|
||||||
|
|
||||||
|
##### Log Level
|
||||||
|
- The `log_level` key is used to set the log level of the application. The default value is `info`
|
||||||
|
- The log level can be set to `debug`, `info`, `warn`, `error`
|
||||||
##### Max Cache Size
|
##### Max Cache Size
|
||||||
- The `max_cache_size` key is used to set the maximum number of infohashes that can be stored in the availability cache. This is used to prevent round trip to the debrid provider when using the proxy/Qbittorrent
|
- The `max_cache_size` key is used to set the maximum number of infohashes that can be stored in the availability cache. This is used to prevent round trip to the debrid provider when using the proxy/Qbittorrent
|
||||||
- The default value is `1000`
|
- The default value is `1000`
|
||||||
@@ -161,7 +191,7 @@ The `repair` key is used to enable the repair worker
|
|||||||
##### Proxy Config
|
##### Proxy Config
|
||||||
- The `enabled` key is used to enable the proxy
|
- The `enabled` key is used to enable the proxy
|
||||||
- The `port` key is the port the proxy will listen on
|
- The `port` key is the port the proxy will listen on
|
||||||
- The `debug` key is used to enable debug logs
|
- The `log_level` key is used to set the log level of the proxy. The default value is `info`
|
||||||
- The `username` and `password` keys are used for basic authentication
|
- The `username` and `password` keys are used for basic authentication
|
||||||
- The `cached_only` means only cached torrents will be returned
|
- The `cached_only` means only cached torrents will be returned
|
||||||
|
|
||||||
@@ -180,40 +210,13 @@ This is particularly useful if you want to use the Repair tool without using Qbi
|
|||||||
- The `host` key is the host of the Arr
|
- The `host` key is the host of the Arr
|
||||||
- The `token` key is the API token of the Arr
|
- The `token` key is the API token of the Arr
|
||||||
|
|
||||||
|
|
||||||
### Proxy
|
### Proxy
|
||||||
|
|
||||||
The proxy is useful in filtering out un-cached Real Debrid torrents.
|
The proxy is useful in filtering out un-cached Real Debrid torrents.
|
||||||
The proxy is a simple HTTP proxy that requires basic authentication. The proxy can be enabled by setting the `proxy.enabled` to `true` in the config file.
|
The proxy is a simple HTTP proxy that requires basic authentication. The proxy can be enabled by setting the `proxy.enabled` to `true` in the config file.
|
||||||
The proxy listens on the port `8181` by default. The username and password can be set in the config file.
|
The proxy listens on the port `8181` by default. The username and password can be set in the config file.
|
||||||
|
|
||||||
Setting Up Proxy in Arr
|
|
||||||
|
|
||||||
- Sonarr/Radarr
|
|
||||||
- Settings -> General -> Use Proxy
|
|
||||||
- Hostname: `localhost` # or the IP of the server
|
|
||||||
- Port: `8181` # or the port set in the config file
|
|
||||||
- Username: `username` # or the username set in the config file
|
|
||||||
- Password: `password` # or the password set in the config file
|
|
||||||
- Bypass Proxy for Local Addresses -> `No`
|
|
||||||
|
|
||||||
### Qbittorrent
|
|
||||||
|
|
||||||
The qBittorrent is a mock qBittorrent API that supports the Arrs(Sonarr, Radarr, etc).
|
|
||||||
|
|
||||||
Setting Up Qbittorrent in Arr
|
|
||||||
|
|
||||||
- Sonarr/Radarr
|
|
||||||
- Settings -> Download Client -> Add Client -> qBittorrent
|
|
||||||
- Host: `localhost` # or the IP of the server
|
|
||||||
- Port: `8282` # or the port set in the config file/ docker-compose env
|
|
||||||
- Username: `http://sonarr:8989` # Your arr host with http/https
|
|
||||||
- Password: `sonarr_token` # Your arr token
|
|
||||||
- Category: e.g `sonarr`, `radarr`
|
|
||||||
- Use SSL -> `No`
|
|
||||||
- Sequential Download -> `No`|`Yes` (If you want to download the torrents locally instead of symlink)
|
|
||||||
- Test
|
|
||||||
- Save
|
|
||||||
|
|
||||||
### Repair Worker
|
### Repair Worker
|
||||||
|
|
||||||
The repair worker is a simple worker that checks for missing files in the Arrs(Sonarr, Radarr, etc). It's particularly useful for files either deleted by the Debrid provider or files with bad symlinks.
|
The repair worker is a simple worker that checks for missing files in the Arrs(Sonarr, Radarr, etc). It's particularly useful for files either deleted by the Debrid provider or files with bad symlinks.
|
||||||
@@ -222,9 +225,15 @@ The repair worker is a simple worker that checks for missing files in the Arrs(S
|
|||||||
- Search for missing files
|
- Search for missing files
|
||||||
- Search for deleted/unreadable files
|
- Search for deleted/unreadable files
|
||||||
|
|
||||||
|
|
||||||
|
### Changelog
|
||||||
|
|
||||||
|
- View the [CHANGELOG.md](CHANGELOG.md) for the latest changes
|
||||||
|
|
||||||
|
|
||||||
### TODO
|
### TODO
|
||||||
- [ ] A proper name!!!!
|
- [ ] A proper name!!!!
|
||||||
- [ ] Debrid
|
- [x] Debrid
|
||||||
- [x] Add more Debrid Providers
|
- [x] Add more Debrid Providers
|
||||||
|
|
||||||
- [ ] Qbittorrent
|
- [ ] Qbittorrent
|
||||||
|
|||||||
+3
-2
@@ -22,7 +22,7 @@ type DebridConfig struct {
|
|||||||
type ProxyConfig struct {
|
type ProxyConfig struct {
|
||||||
Port string `json:"port"`
|
Port string `json:"port"`
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
Debug bool `json:"debug"`
|
LogLevel string `json:"log_level"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
CachedOnly *bool `json:"cached_only"`
|
CachedOnly *bool `json:"cached_only"`
|
||||||
@@ -32,7 +32,7 @@ type QBitTorrentConfig struct {
|
|||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Port string `json:"port"`
|
Port string `json:"port"`
|
||||||
Debug bool `json:"debug"`
|
LogLevel string `json:"log_level"`
|
||||||
DownloadFolder string `json:"download_folder"`
|
DownloadFolder string `json:"download_folder"`
|
||||||
Categories []string `json:"categories"`
|
Categories []string `json:"categories"`
|
||||||
RefreshInterval int `json:"refresh_interval"`
|
RefreshInterval int `json:"refresh_interval"`
|
||||||
@@ -51,6 +51,7 @@ type RepairConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
LogLevel string `json:"log_level"`
|
||||||
Debrid DebridConfig `json:"debrid"`
|
Debrid DebridConfig `json:"debrid"`
|
||||||
Debrids []DebridConfig `json:"debrids"`
|
Debrids []DebridConfig `json:"debrids"`
|
||||||
Proxy ProxyConfig `json:"proxy"`
|
Proxy ProxyConfig `json:"proxy"`
|
||||||
|
|||||||
+33
-6
@@ -2,13 +2,40 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"github.com/rs/zerolog"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLogger(prefix string, output *os.File) *log.Logger {
|
func NewLogger(prefix string, level string, output *os.File) zerolog.Logger {
|
||||||
f := fmt.Sprintf("[%s] ", prefix)
|
writer := zerolog.ConsoleWriter{
|
||||||
return log.New(output, f, log.LstdFlags)
|
Out: output,
|
||||||
}
|
TimeFormat: "2006-01-02 15:04:05",
|
||||||
|
NoColor: false, // Set to true if you don't want colors
|
||||||
|
FormatLevel: func(i interface{}) string {
|
||||||
|
return strings.ToUpper(fmt.Sprintf("| %-6s|", i))
|
||||||
|
},
|
||||||
|
FormatMessage: func(i interface{}) string {
|
||||||
|
return fmt.Sprintf("[%s] %v", prefix, i)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
var Logger = NewLogger("Main", os.Stdout)
|
logger := zerolog.New(writer).
|
||||||
|
With().
|
||||||
|
Timestamp().
|
||||||
|
Logger().
|
||||||
|
Level(zerolog.InfoLevel)
|
||||||
|
|
||||||
|
// Set the log level
|
||||||
|
switch level {
|
||||||
|
case "debug":
|
||||||
|
logger = logger.Level(zerolog.DebugLevel)
|
||||||
|
case "info":
|
||||||
|
logger = logger.Level(zerolog.InfoLevel)
|
||||||
|
case "warn":
|
||||||
|
logger = logger.Level(zerolog.WarnLevel)
|
||||||
|
case "error":
|
||||||
|
logger = logger.Level(zerolog.ErrorLevel)
|
||||||
|
}
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 185 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 197 KiB |
@@ -22,7 +22,11 @@ require (
|
|||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/huandu/xstrings v1.3.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
|
github.com/rs/zerolog v1.33.0 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/net v0.27.0 // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/text v0.16.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIH
|
|||||||
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -79,6 +80,7 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
@@ -136,6 +138,11 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -175,6 +182,9 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn
|
|||||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
|
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
|
||||||
|
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
@@ -241,6 +251,11 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ func (a *Arr) GetMedia(tvId string) ([]Content, error) {
|
|||||||
}
|
}
|
||||||
if resp.StatusCode == http.StatusNotFound {
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
// This is Radarr
|
// This is Radarr
|
||||||
log.Printf("Radarr detected\n")
|
log.Printf("Radarr detected")
|
||||||
a.Type = Radarr
|
a.Type = Radarr
|
||||||
return GetMovies(a, tvId)
|
return GetMovies(a, tvId)
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-15
@@ -1,9 +1,9 @@
|
|||||||
package arr
|
package arr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
repairLogger *log.Logger = common.NewLogger("Repair", os.Stdout)
|
repairLogger zerolog.Logger = common.NewLogger("repair", "info", os.Stdout)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *Arr) SearchMissing(id int) {
|
func (a *Arr) SearchMissing(id int) {
|
||||||
@@ -37,40 +37,41 @@ func (a *Arr) SearchMissing(id int) {
|
|||||||
MovieId: id,
|
MovieId: id,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
repairLogger.Printf("Unknown arr type: %s\n", a.Type)
|
repairLogger.Info().Msgf("Unknown arr type: %s", a.Type)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := a.Request(http.MethodPost, "api/v3/command", payload)
|
resp, err := a.Request(http.MethodPost, "api/v3/command", payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
repairLogger.Printf("Failed to search missing: %v\n", err)
|
repairLogger.Info().Msgf("Failed to search missing: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if statusOk := strconv.Itoa(resp.StatusCode)[0] == '2'; !statusOk {
|
if statusOk := strconv.Itoa(resp.StatusCode)[0] == '2'; !statusOk {
|
||||||
repairLogger.Printf("Failed to search missing: %s\n", resp.Status)
|
repairLogger.Info().Msgf("Failed to search missing: %s", resp.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Arr) Repair(tmdbId string) error {
|
func (a *Arr) Repair(tmdbId string) error {
|
||||||
|
|
||||||
repairLogger.Printf("Starting repair for %s\n", a.Name)
|
repairLogger.Info().Msgf("Starting repair for %s", a.Name)
|
||||||
media, err := a.GetMedia(tmdbId)
|
media, err := a.GetMedia(tmdbId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
repairLogger.Printf("Failed to get %s media: %v\n", a.Type, err)
|
repairLogger.Info().Msgf("Failed to get %s media: %v", a.Type, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
repairLogger.Printf("Found %d %s media\n", len(media), a.Type)
|
repairLogger.Info().Msgf("Found %d %s media", len(media), a.Type)
|
||||||
|
|
||||||
brokenMedia := a.processMedia(media)
|
brokenMedia := a.processMedia(media)
|
||||||
repairLogger.Printf("Found %d %s broken media files\n", len(brokenMedia), a.Type)
|
repairLogger.Info().Msgf("Found %d %s broken media files", len(brokenMedia), a.Type)
|
||||||
|
|
||||||
// Automatic search for missing files
|
// Automatic search for missing files
|
||||||
for _, m := range brokenMedia {
|
for _, m := range brokenMedia {
|
||||||
|
repairLogger.Debug().Msgf("Searching missing for %s", m.Title)
|
||||||
a.SearchMissing(m.Id)
|
a.SearchMissing(m.Id)
|
||||||
}
|
}
|
||||||
repairLogger.Printf("Search missing completed for %s\n", a.Name)
|
repairLogger.Info().Msgf("Search missing completed for %s", a.Name)
|
||||||
repairLogger.Printf("Repair completed for %s\n", a.Name)
|
repairLogger.Info().Msgf("Repair completed for %s", a.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,19 +146,24 @@ func (a *Arr) checkMediaFilesParallel(m Content) bool {
|
|||||||
go func() {
|
go func() {
|
||||||
defer fileWg.Done()
|
defer fileWg.Done()
|
||||||
for f := range fileJobs {
|
for f := range fileJobs {
|
||||||
|
repairLogger.Debug().Msgf("Checking file: %s", f.Path)
|
||||||
isBroken := false
|
isBroken := false
|
||||||
if fileIsSymlinked(f.Path) {
|
if fileIsSymlinked(f.Path) {
|
||||||
|
repairLogger.Debug().Msgf("File is symlinked: %s", f.Path)
|
||||||
if !fileIsCorrectSymlink(f.Path) {
|
if !fileIsCorrectSymlink(f.Path) {
|
||||||
|
repairLogger.Debug().Msgf("File is broken: %s", f.Path)
|
||||||
isBroken = true
|
isBroken = true
|
||||||
if err := a.DeleteFile(f.Id); err != nil {
|
if err := a.DeleteFile(f.Id); err != nil {
|
||||||
repairLogger.Printf("Failed to delete file: %s %d: %v\n", f.Path, f.Id, err)
|
repairLogger.Info().Msgf("Failed to delete file: %s %d: %v", f.Path, f.Id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
repairLogger.Debug().Msgf("File is not symlinked: %s", f.Path)
|
||||||
if !fileIsReadable(f.Path) {
|
if !fileIsReadable(f.Path) {
|
||||||
|
repairLogger.Debug().Msgf("File is broken: %s", f.Path)
|
||||||
isBroken = true
|
isBroken = true
|
||||||
if err := a.DeleteFile(f.Id); err != nil {
|
if err := a.DeleteFile(f.Id); err != nil {
|
||||||
repairLogger.Printf("Failed to delete file: %s %d: %v\n", f.Path, f.Id, err)
|
repairLogger.Info().Msgf("Failed to delete file: %s %d: %v", f.Path, f.Id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,14 +201,14 @@ func (a *Arr) checkMediaFiles(m Content) bool {
|
|||||||
if !fileIsCorrectSymlink(f.Path) {
|
if !fileIsCorrectSymlink(f.Path) {
|
||||||
isBroken = true
|
isBroken = true
|
||||||
if err := a.DeleteFile(f.Id); err != nil {
|
if err := a.DeleteFile(f.Id); err != nil {
|
||||||
repairLogger.Printf("Failed to delete file: %s %d: %v\n", f.Path, f.Id, err)
|
repairLogger.Info().Msgf("Failed to delete file: %s %d: %v", f.Path, f.Id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !fileIsReadable(f.Path) {
|
if !fileIsReadable(f.Path) {
|
||||||
isBroken = true
|
isBroken = true
|
||||||
if err := a.DeleteFile(f.Id); err != nil {
|
if err := a.DeleteFile(f.Id); err != nil {
|
||||||
repairLogger.Printf("Failed to delete file: %s %d: %v\n", f.Path, f.Id, err)
|
repairLogger.Info().Msgf("Failed to delete file: %s %d: %v", f.Path, f.Id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package debrid
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
gourl "net/url"
|
gourl "net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -25,7 +25,7 @@ func (r *AllDebrid) GetName() string {
|
|||||||
return r.Name
|
return r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *AllDebrid) GetLogger() *log.Logger {
|
func (r *AllDebrid) GetLogger() zerolog.Logger {
|
||||||
return r.logger
|
return r.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ func (r *AllDebrid) SubmitMagnet(torrent *Torrent) (*Torrent, error) {
|
|||||||
}
|
}
|
||||||
magnet := magnets[0]
|
magnet := magnets[0]
|
||||||
torrentId := strconv.Itoa(magnet.ID)
|
torrentId := strconv.Itoa(magnet.ID)
|
||||||
r.logger.Printf("Torrent: %s added with id: %s\n", torrent.Name, torrentId)
|
r.logger.Info().Msgf("Torrent: %s added with id: %s", torrent.Name, torrentId)
|
||||||
torrent.Id = torrentId
|
torrent.Id = torrentId
|
||||||
|
|
||||||
return torrent, nil
|
return torrent, nil
|
||||||
@@ -129,7 +129,7 @@ func (r *AllDebrid) GetTorrent(id string) (*Torrent, error) {
|
|||||||
var res structs.AllDebridTorrentInfoResponse
|
var res structs.AllDebridTorrentInfoResponse
|
||||||
err = json.Unmarshal(resp, &res)
|
err = json.Unmarshal(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Printf("Error unmarshalling torrent info: %s\n", err)
|
r.logger.Info().Msgf("Error unmarshalling torrent info: %s", err)
|
||||||
return torrent, err
|
return torrent, err
|
||||||
}
|
}
|
||||||
data := res.Data.Magnets
|
data := res.Data.Magnets
|
||||||
@@ -169,7 +169,7 @@ func (r *AllDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, err
|
|||||||
}
|
}
|
||||||
status := torrent.Status
|
status := torrent.Status
|
||||||
if status == "downloaded" {
|
if status == "downloaded" {
|
||||||
r.logger.Printf("Torrent: %s downloaded\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s downloaded", torrent.Name)
|
||||||
if !isSymlink {
|
if !isSymlink {
|
||||||
err = r.GetDownloadLinks(torrent)
|
err = r.GetDownloadLinks(torrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -198,9 +198,9 @@ func (r *AllDebrid) DeleteTorrent(torrent *Torrent) {
|
|||||||
req, _ := http.NewRequest(http.MethodGet, url, nil)
|
req, _ := http.NewRequest(http.MethodGet, url, nil)
|
||||||
_, err := r.client.MakeRequest(req)
|
_, err := r.client.MakeRequest(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r.logger.Printf("Torrent: %s deleted\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s deleted", torrent.Name)
|
||||||
} else {
|
} else {
|
||||||
r.logger.Printf("Error deleting torrent: %s", err)
|
r.logger.Info().Msgf("Error deleting torrent: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ func NewAllDebrid(dc common.DebridConfig, cache *common.Cache) *AllDebrid {
|
|||||||
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
||||||
}
|
}
|
||||||
client := common.NewRLHTTPClient(rl, headers)
|
client := common.NewRLHTTPClient(rl, headers)
|
||||||
logger := common.NewLogger(dc.Name, os.Stdout)
|
logger := common.NewLogger(dc.Name, common.CONFIG.LogLevel, os.Stdout)
|
||||||
return &AllDebrid{
|
return &AllDebrid{
|
||||||
BaseDebrid: BaseDebrid{
|
BaseDebrid: BaseDebrid{
|
||||||
Name: "alldebrid",
|
Name: "alldebrid",
|
||||||
|
|||||||
+11
-9
@@ -3,9 +3,9 @@ package debrid
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
||||||
"log"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ type BaseDebrid struct {
|
|||||||
client *common.RLHTTPClient
|
client *common.RLHTTPClient
|
||||||
cache *common.Cache
|
cache *common.Cache
|
||||||
MountPath string
|
MountPath string
|
||||||
logger *log.Logger
|
logger zerolog.Logger
|
||||||
CheckCached bool
|
CheckCached bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ type Service interface {
|
|||||||
GetCheckCached() bool
|
GetCheckCached() bool
|
||||||
GetTorrent(id string) (*Torrent, error)
|
GetTorrent(id string) (*Torrent, error)
|
||||||
GetName() string
|
GetName() string
|
||||||
GetLogger() *log.Logger
|
GetLogger() zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDebrid(debs []common.DebridConfig, maxCachedSize int) *DebridService {
|
func NewDebrid(debs []common.DebridConfig, maxCachedSize int) *DebridService {
|
||||||
@@ -41,7 +41,8 @@ func NewDebrid(debs []common.DebridConfig, maxCachedSize int) *DebridService {
|
|||||||
|
|
||||||
for _, dc := range debs {
|
for _, dc := range debs {
|
||||||
d := createDebrid(dc, common.NewCache(maxCacheSize))
|
d := createDebrid(dc, common.NewCache(maxCacheSize))
|
||||||
d.GetLogger().Println("Debrid Service started")
|
logger := d.GetLogger()
|
||||||
|
logger.Info().Msg("Debrid Service started")
|
||||||
debrids = append(debrids, d)
|
debrids = append(debrids, d)
|
||||||
}
|
}
|
||||||
d := &DebridService{debrids: debrids, lastUsed: 0}
|
d := &DebridService{debrids: debrids, lastUsed: 0}
|
||||||
@@ -156,16 +157,17 @@ func ProcessTorrent(d *DebridService, magnet *common.Magnet, a *arr.Arr, isSymli
|
|||||||
errs := make([]error, 0)
|
errs := make([]error, 0)
|
||||||
|
|
||||||
for index, db := range d.debrids {
|
for index, db := range d.debrids {
|
||||||
log.Println("Processing debrid: ", db.GetName())
|
|
||||||
logger := db.GetLogger()
|
logger := db.GetLogger()
|
||||||
logger.Printf("Torrent Hash: %s", debridTorrent.InfoHash)
|
logger.Info().Msgf("Processing debrid: %s", db.GetName())
|
||||||
|
|
||||||
|
logger.Info().Msgf("Torrent Hash: %s", debridTorrent.InfoHash)
|
||||||
if db.GetCheckCached() {
|
if db.GetCheckCached() {
|
||||||
hash, exists := db.IsAvailable([]string{debridTorrent.InfoHash})[debridTorrent.InfoHash]
|
hash, exists := db.IsAvailable([]string{debridTorrent.InfoHash})[debridTorrent.InfoHash]
|
||||||
if !exists || !hash {
|
if !exists || !hash {
|
||||||
logger.Printf("Torrent: %s is not cached", debridTorrent.Name)
|
logger.Info().Msgf("Torrent: %s is not cached", debridTorrent.Name)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
logger.Printf("Torrent: %s is cached(or downloading)", debridTorrent.Name)
|
logger.Info().Msgf("Torrent: %s is cached(or downloading)", debridTorrent.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +180,7 @@ func ProcessTorrent(d *DebridService, magnet *common.Magnet, a *arr.Arr, isSymli
|
|||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logger.Printf("Torrent: %s submitted to %s", dbt.Name, db.GetName())
|
logger.Info().Msgf("Torrent: %s submitted to %s", dbt.Name, db.GetName())
|
||||||
d.lastUsed = index
|
d.lastUsed = index
|
||||||
return db.CheckStatus(dbt, isSymlink)
|
return db.CheckStatus(dbt, isSymlink)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
||||||
"log"
|
"log"
|
||||||
@@ -24,7 +25,7 @@ func (r *DebridLink) GetName() string {
|
|||||||
return r.Name
|
return r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *DebridLink) GetLogger() *log.Logger {
|
func (r *DebridLink) GetLogger() zerolog.Logger {
|
||||||
return r.logger
|
return r.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,13 +64,13 @@ func (r *DebridLink) IsAvailable(infohashes []string) map[string]bool {
|
|||||||
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 {
|
||||||
log.Println("Error checking availability:", err)
|
r.logger.Info().Msgf("Error checking availability: %v", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
var data structs.DebridLinkAvailableResponse
|
var data structs.DebridLinkAvailableResponse
|
||||||
err = json.Unmarshal(resp, &data)
|
err = json.Unmarshal(resp, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error marshalling availability:", err)
|
r.logger.Info().Msgf("Error marshalling availability: %v", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
if data.Value == nil {
|
if data.Value == nil {
|
||||||
@@ -159,7 +160,7 @@ func (r *DebridLink) SubmitMagnet(torrent *Torrent) (*Torrent, error) {
|
|||||||
}
|
}
|
||||||
data := *res.Value
|
data := *res.Value
|
||||||
status := "downloading"
|
status := "downloading"
|
||||||
log.Printf("Torrent: %s added with id: %s\n", torrent.Name, data.ID)
|
log.Printf("Torrent: %s added with id: %s", torrent.Name, data.ID)
|
||||||
name := common.RemoveInvalidChars(data.Name)
|
name := common.RemoveInvalidChars(data.Name)
|
||||||
torrent.Id = data.ID
|
torrent.Id = data.ID
|
||||||
torrent.Name = name
|
torrent.Name = name
|
||||||
@@ -197,7 +198,7 @@ func (r *DebridLink) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
|
|||||||
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", torrent.Name)
|
||||||
} else if status == "downloaded" {
|
} else if status == "downloaded" {
|
||||||
r.logger.Printf("Torrent: %s downloaded\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s downloaded", torrent.Name)
|
||||||
if !isSymlink {
|
if !isSymlink {
|
||||||
err = r.GetDownloadLinks(torrent)
|
err = r.GetDownloadLinks(torrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -224,9 +225,9 @@ func (r *DebridLink) DeleteTorrent(torrent *Torrent) {
|
|||||||
req, _ := http.NewRequest(http.MethodDelete, url, nil)
|
req, _ := http.NewRequest(http.MethodDelete, url, nil)
|
||||||
_, err := r.client.MakeRequest(req)
|
_, err := r.client.MakeRequest(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r.logger.Printf("Torrent: %s deleted\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s deleted", torrent.Name)
|
||||||
} else {
|
} else {
|
||||||
r.logger.Printf("Error deleting torrent: %s", err)
|
r.logger.Info().Msgf("Error deleting torrent: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +255,7 @@ func NewDebridLink(dc common.DebridConfig, cache *common.Cache) *DebridLink {
|
|||||||
"Content-Type": "application/json",
|
"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, common.CONFIG.LogLevel, os.Stdout)
|
||||||
return &DebridLink{
|
return &DebridLink{
|
||||||
BaseDebrid: BaseDebrid{
|
BaseDebrid: BaseDebrid{
|
||||||
Name: "debridlink",
|
Name: "debridlink",
|
||||||
|
|||||||
+10
-10
@@ -3,9 +3,9 @@ package debrid
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
gourl "net/url"
|
gourl "net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -27,7 +27,7 @@ func (r *RealDebrid) GetName() string {
|
|||||||
return r.Name
|
return r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RealDebrid) GetLogger() *log.Logger {
|
func (r *RealDebrid) GetLogger() zerolog.Logger {
|
||||||
return r.logger
|
return r.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,13 +89,13 @@ func (r *RealDebrid) IsAvailable(infohashes []string) map[string]bool {
|
|||||||
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 {
|
||||||
log.Println("Error checking availability:", err)
|
r.logger.Info().Msgf("Error checking availability: %v", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
var data structs.RealDebridAvailabilityResponse
|
var data structs.RealDebridAvailabilityResponse
|
||||||
err = json.Unmarshal(resp, &data)
|
err = json.Unmarshal(resp, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error marshalling availability:", err)
|
r.logger.Info().Msgf("Error marshalling availability: %v", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
for _, h := range hashes[i:end] {
|
for _, h := range hashes[i:end] {
|
||||||
@@ -121,7 +121,7 @@ func (r *RealDebrid) SubmitMagnet(torrent *Torrent) (*Torrent, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(resp, &data)
|
err = json.Unmarshal(resp, &data)
|
||||||
log.Printf("Torrent: %s added with id: %s\n", torrent.Name, data.Id)
|
r.logger.Info().Msgf("Torrent: %s added with id: %s", torrent.Name, data.Id)
|
||||||
torrent.Id = data.Id
|
torrent.Id = data.Id
|
||||||
|
|
||||||
return torrent, nil
|
return torrent, nil
|
||||||
@@ -164,7 +164,7 @@ func (r *RealDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
|
|||||||
for {
|
for {
|
||||||
resp, err := r.client.MakeRequest(req)
|
resp, err := r.client.MakeRequest(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERROR Checking file: ", err)
|
r.logger.Info().Msgf("ERROR Checking file: %v", err)
|
||||||
return torrent, err
|
return torrent, err
|
||||||
}
|
}
|
||||||
var data structs.RealDebridTorrentInfo
|
var data structs.RealDebridTorrentInfo
|
||||||
@@ -207,7 +207,7 @@ func (r *RealDebrid) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, er
|
|||||||
} else if status == "downloaded" {
|
} else if status == "downloaded" {
|
||||||
files := GetTorrentFiles(data)
|
files := GetTorrentFiles(data)
|
||||||
torrent.Files = files
|
torrent.Files = files
|
||||||
log.Printf("Torrent: %s downloaded to RD\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s downloaded to RD", torrent.Name)
|
||||||
if !isSymlink {
|
if !isSymlink {
|
||||||
err = r.GetDownloadLinks(torrent)
|
err = r.GetDownloadLinks(torrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -233,9 +233,9 @@ func (r *RealDebrid) DeleteTorrent(torrent *Torrent) {
|
|||||||
req, _ := http.NewRequest(http.MethodDelete, url, nil)
|
req, _ := http.NewRequest(http.MethodDelete, url, nil)
|
||||||
_, err := r.client.MakeRequest(req)
|
_, err := r.client.MakeRequest(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r.logger.Printf("Torrent: %s deleted\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s deleted", torrent.Name)
|
||||||
} else {
|
} else {
|
||||||
r.logger.Printf("Error deleting torrent: %s", err)
|
r.logger.Info().Msgf("Error deleting torrent: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ func NewRealDebrid(dc common.DebridConfig, cache *common.Cache) *RealDebrid {
|
|||||||
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
||||||
}
|
}
|
||||||
client := common.NewRLHTTPClient(rl, headers)
|
client := common.NewRLHTTPClient(rl, headers)
|
||||||
logger := common.NewLogger(dc.Name, os.Stdout)
|
logger := common.NewLogger(dc.Name, common.CONFIG.LogLevel, os.Stdout)
|
||||||
return &RealDebrid{
|
return &RealDebrid{
|
||||||
BaseDebrid: BaseDebrid{
|
BaseDebrid: BaseDebrid{
|
||||||
Name: "realdebrid",
|
Name: "realdebrid",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid/structs"
|
||||||
"log"
|
"log"
|
||||||
@@ -30,7 +31,7 @@ func (r *Torbox) GetName() string {
|
|||||||
return r.Name
|
return r.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Torbox) GetLogger() *log.Logger {
|
func (r *Torbox) GetLogger() zerolog.Logger {
|
||||||
return r.logger
|
return r.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +70,13 @@ func (r *Torbox) IsAvailable(infohashes []string) map[string]bool {
|
|||||||
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 {
|
||||||
log.Println("Error checking availability:", err)
|
r.logger.Info().Msgf("Error checking availability: %v", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
var res structs.TorBoxAvailableResponse
|
var res structs.TorBoxAvailableResponse
|
||||||
err = json.Unmarshal(resp, &res)
|
err = json.Unmarshal(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error marshalling availability:", err)
|
r.logger.Info().Msgf("Error marshalling availability: %v", err)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
if res.Data == nil {
|
if res.Data == nil {
|
||||||
@@ -117,7 +118,7 @@ func (r *Torbox) SubmitMagnet(torrent *Torrent) (*Torrent, error) {
|
|||||||
}
|
}
|
||||||
dt := *data.Data
|
dt := *data.Data
|
||||||
torrentId := strconv.Itoa(dt.Id)
|
torrentId := strconv.Itoa(dt.Id)
|
||||||
log.Printf("Torrent: %s added with id: %s\n", torrent.Name, torrentId)
|
log.Printf("Torrent: %s added with id: %s", torrent.Name, torrentId)
|
||||||
torrent.Id = torrentId
|
torrent.Id = torrentId
|
||||||
|
|
||||||
return torrent, nil
|
return torrent, nil
|
||||||
@@ -208,7 +209,7 @@ func (r *Torbox) CheckStatus(torrent *Torrent, isSymlink bool) (*Torrent, error)
|
|||||||
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", torrent.Name)
|
||||||
} else if status == "downloaded" {
|
} else if status == "downloaded" {
|
||||||
r.logger.Printf("Torrent: %s downloaded\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s downloaded", torrent.Name)
|
||||||
if !isSymlink {
|
if !isSymlink {
|
||||||
err = r.GetDownloadLinks(torrent)
|
err = r.GetDownloadLinks(torrent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -237,9 +238,9 @@ func (r *Torbox) DeleteTorrent(torrent *Torrent) {
|
|||||||
req, _ := http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(jsonPayload))
|
req, _ := http.NewRequest(http.MethodDelete, url, bytes.NewBuffer(jsonPayload))
|
||||||
_, err := r.client.MakeRequest(req)
|
_, err := r.client.MakeRequest(req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r.logger.Printf("Torrent: %s deleted\n", torrent.Name)
|
r.logger.Info().Msgf("Torrent: %s deleted", torrent.Name)
|
||||||
} else {
|
} else {
|
||||||
r.logger.Printf("Error deleting torrent: %s", err)
|
r.logger.Info().Msgf("Error deleting torrent: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +289,7 @@ func NewTorbox(dc common.DebridConfig, cache *common.Cache) *Torbox {
|
|||||||
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
"Authorization": fmt.Sprintf("Bearer %s", dc.APIKey),
|
||||||
}
|
}
|
||||||
client := common.NewRLHTTPClient(rl, headers)
|
client := common.NewRLHTTPClient(rl, headers)
|
||||||
logger := common.NewLogger(dc.Name, os.Stdout)
|
logger := common.NewLogger(dc.Name, common.CONFIG.LogLevel, os.Stdout)
|
||||||
return &Torbox{
|
return &Torbox{
|
||||||
BaseDebrid: BaseDebrid{
|
BaseDebrid: BaseDebrid{
|
||||||
Name: "torbox",
|
Name: "torbox",
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ Loop:
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
fmt.Printf(" %s: transferred %d / %d bytes (%.2f%%)\n",
|
fmt.Printf(" %s: transferred %d / %d bytes (%.2f%%)",
|
||||||
resp.Filename,
|
resp.Filename,
|
||||||
resp.BytesComplete(),
|
resp.BytesComplete(),
|
||||||
resp.Size(),
|
resp.Size(),
|
||||||
|
|||||||
+11
-12
@@ -9,11 +9,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/elazarl/goproxy"
|
"github.com/elazarl/goproxy"
|
||||||
"github.com/elazarl/goproxy/ext/auth"
|
"github.com/elazarl/goproxy/ext/auth"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
||||||
"github.com/valyala/fastjson"
|
"github.com/valyala/fastjson"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -75,7 +75,7 @@ type Proxy struct {
|
|||||||
password string
|
password string
|
||||||
cachedOnly bool
|
cachedOnly bool
|
||||||
debrid debrid.Service
|
debrid debrid.Service
|
||||||
logger *log.Logger
|
logger zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy(config common.Config, deb *debrid.DebridService) *Proxy {
|
func NewProxy(config common.Config, deb *debrid.DebridService) *Proxy {
|
||||||
@@ -84,12 +84,11 @@ func NewProxy(config common.Config, deb *debrid.DebridService) *Proxy {
|
|||||||
return &Proxy{
|
return &Proxy{
|
||||||
port: port,
|
port: port,
|
||||||
enabled: cfg.Enabled,
|
enabled: cfg.Enabled,
|
||||||
debug: cfg.Debug,
|
|
||||||
username: cfg.Username,
|
username: cfg.Username,
|
||||||
password: cfg.Password,
|
password: cfg.Password,
|
||||||
cachedOnly: *cfg.CachedOnly,
|
cachedOnly: *cfg.CachedOnly,
|
||||||
debrid: deb.Get(),
|
debrid: deb.Get(),
|
||||||
logger: common.NewLogger("Proxy", os.Stdout),
|
logger: common.NewLogger("Proxy", cfg.LogLevel, os.Stdout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +228,7 @@ func (p *Proxy) ProcessXMLResponse(resp *http.Response) *http.Response {
|
|||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.logger.Println("Error reading response body:", err)
|
p.logger.Info().Msgf("Error reading response body: %v", err)
|
||||||
resp.Body = io.NopCloser(bytes.NewReader(body))
|
resp.Body = io.NopCloser(bytes.NewReader(body))
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
@@ -241,7 +240,7 @@ func (p *Proxy) ProcessXMLResponse(resp *http.Response) *http.Response {
|
|||||||
var rss RSS
|
var rss RSS
|
||||||
err = xml.Unmarshal(body, &rss)
|
err = xml.Unmarshal(body, &rss)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.logger.Printf("Error unmarshalling XML: %v", err)
|
p.logger.Info().Msgf("Error unmarshalling XML: %v", err)
|
||||||
resp.Body = io.NopCloser(bytes.NewReader(body))
|
resp.Body = io.NopCloser(bytes.NewReader(body))
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
@@ -279,10 +278,10 @@ func (p *Proxy) ProcessXMLResponse(resp *http.Response) *http.Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(newItems) > 0 {
|
if len(newItems) > 0 {
|
||||||
p.logger.Printf("[%s Report]: %d/%d items are cached || Found %d infohash", indexer, len(newItems), len(rss.Channel.Items), len(hashes))
|
p.logger.Info().Msgf("[%s Report]: %d/%d items are cached || Found %d infohash", indexer, len(newItems), len(rss.Channel.Items), len(hashes))
|
||||||
} else {
|
} else {
|
||||||
// This will prevent the indexer from being disabled by the arr
|
// This will prevent the indexer from being disabled by the arr
|
||||||
p.logger.Printf("[%s Report]: No Items are cached; Return only first item with [UnCached]", indexer)
|
p.logger.Info().Msgf("[%s Report]: No Items are cached; Return only first item with [UnCached]", indexer)
|
||||||
item := rss.Channel.Items[0]
|
item := rss.Channel.Items[0]
|
||||||
item.Title = fmt.Sprintf("%s [UnCached]", item.Title)
|
item.Title = fmt.Sprintf("%s [UnCached]", item.Title)
|
||||||
newItems = append(newItems, item)
|
newItems = append(newItems, item)
|
||||||
@@ -291,7 +290,7 @@ func (p *Proxy) ProcessXMLResponse(resp *http.Response) *http.Response {
|
|||||||
rss.Channel.Items = newItems
|
rss.Channel.Items = newItems
|
||||||
modifiedBody, err := xml.MarshalIndent(rss, "", " ")
|
modifiedBody, err := xml.MarshalIndent(rss, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.logger.Printf("Error marshalling XML: %v", err)
|
p.logger.Info().Msgf("Error marshalling XML: %v", err)
|
||||||
resp.Body = io.NopCloser(bytes.NewReader(body))
|
resp.Body = io.NopCloser(bytes.NewReader(body))
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
@@ -332,13 +331,13 @@ func (p *Proxy) Start(ctx context.Context) error {
|
|||||||
Addr: portFmt,
|
Addr: portFmt,
|
||||||
Handler: proxy,
|
Handler: proxy,
|
||||||
}
|
}
|
||||||
p.logger.Printf("[*] Starting proxy server on %s\n", portFmt)
|
p.logger.Info().Msgf("Starting proxy server on %s", portFmt)
|
||||||
go func() {
|
go func() {
|
||||||
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
p.logger.Printf("Error starting proxy server: %v\n", err)
|
p.logger.Info().Msgf("Error starting proxy server: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
p.logger.Println("Shutting down gracefully...")
|
p.logger.Info().Msg("Shutting down gracefully...")
|
||||||
return srv.Shutdown(context.Background())
|
return srv.Shutdown(context.Background())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
|
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
type qbitHandler struct {
|
type qbitHandler struct {
|
||||||
qbit *shared.QBit
|
qbit *shared.QBit
|
||||||
logger *log.Logger
|
logger zerolog.Logger
|
||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,21 +148,21 @@ func (q *qbitHandler) handleTorrentsAdd(w http.ResponseWriter, r *http.Request)
|
|||||||
case "multipart/form-data":
|
case "multipart/form-data":
|
||||||
err := r.ParseMultipartForm(32 << 20) // 32MB max memory
|
err := r.ParseMultipartForm(32 << 20) // 32MB max memory
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Error parsing form: %v\n", err)
|
q.logger.Info().Msgf("Error parsing form: %v", err)
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case "application/x-www-form-urlencoded":
|
case "application/x-www-form-urlencoded":
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Error parsing form: %v\n", err)
|
q.logger.Info().Msgf("Error parsing form: %v", err)
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isSymlink := strings.ToLower(r.FormValue("sequentialDownload")) != "true"
|
isSymlink := strings.ToLower(r.FormValue("sequentialDownload")) != "true"
|
||||||
q.logger.Printf("isSymlink: %v\n", isSymlink)
|
q.logger.Info().Msgf("isSymlink: %v", isSymlink)
|
||||||
urls := r.FormValue("urls")
|
urls := r.FormValue("urls")
|
||||||
category := r.FormValue("category")
|
category := r.FormValue("category")
|
||||||
atleastOne := false
|
atleastOne := false
|
||||||
@@ -175,7 +175,7 @@ func (q *qbitHandler) 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 := q.qbit.AddMagnet(ctx, url, category); err != nil {
|
if err := q.qbit.AddMagnet(ctx, url, category); err != nil {
|
||||||
q.logger.Printf("Error adding magnet: %v\n", err)
|
q.logger.Info().Msgf("Error adding magnet: %v", err)
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ func (q *qbitHandler) handleTorrentsAdd(w http.ResponseWriter, r *http.Request)
|
|||||||
files := r.MultipartForm.File["torrents"]
|
files := r.MultipartForm.File["torrents"]
|
||||||
for _, fileHeader := range files {
|
for _, fileHeader := range files {
|
||||||
if err := q.qbit.AddTorrent(ctx, fileHeader, category); err != nil {
|
if err := q.qbit.AddTorrent(ctx, fileHeader, category); err != nil {
|
||||||
q.logger.Printf("Error adding torrent: %v\n", err)
|
q.logger.Info().Msgf("Error adding torrent: %v", err)
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,14 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (q *qbitHandler) Routes(r chi.Router) http.Handler {
|
func (q *qbitHandler) Routes(r chi.Router) http.Handler {
|
||||||
r.Route("/api/v2", func(r chi.Router) {
|
r.Route("/api/v2", func(r chi.Router) {
|
||||||
if q.debug {
|
//if q.debug {
|
||||||
r.Use(middleware.Logger)
|
// r.Use(middleware.Logger)
|
||||||
}
|
//}
|
||||||
r.Use(q.CategoryContext)
|
r.Use(q.CategoryContext)
|
||||||
r.Post("/auth/login", q.handleLogin)
|
r.Post("/auth/login", q.handleLogin)
|
||||||
|
|
||||||
@@ -46,9 +45,9 @@ func (q *qbitHandler) Routes(r chi.Router) http.Handler {
|
|||||||
|
|
||||||
func (u *uiHandler) Routes(r chi.Router) http.Handler {
|
func (u *uiHandler) Routes(r chi.Router) http.Handler {
|
||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
if u.debug {
|
//if u.debug {
|
||||||
r.Use(middleware.Logger)
|
// r.Use(middleware.Logger)
|
||||||
}
|
//}
|
||||||
r.Get("/", u.IndexHandler)
|
r.Get("/", u.IndexHandler)
|
||||||
r.Get("/download", u.DownloadHandler)
|
r.Get("/download", u.DownloadHandler)
|
||||||
r.Get("/repair", u.RepairHandler)
|
r.Get("/repair", u.RepairHandler)
|
||||||
|
|||||||
+10
-10
@@ -6,11 +6,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
|
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -19,17 +19,15 @@ import (
|
|||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
qbit *shared.QBit
|
qbit *shared.QBit
|
||||||
logger *log.Logger
|
logger zerolog.Logger
|
||||||
debug bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(config *common.Config, deb *debrid.DebridService, arrs *arr.Storage) *Server {
|
func NewServer(config *common.Config, deb *debrid.DebridService, arrs *arr.Storage) *Server {
|
||||||
logger := common.NewLogger("QBit", os.Stdout)
|
logger := common.NewLogger("QBit", config.QBitTorrent.LogLevel, os.Stdout)
|
||||||
q := shared.NewQBit(config, deb, logger, arrs)
|
q := shared.NewQBit(config, deb, logger, arrs)
|
||||||
return &Server{
|
return &Server{
|
||||||
qbit: q,
|
qbit: q,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
debug: config.QBitTorrent.Debug,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +35,10 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
r.Use(middleware.Recoverer)
|
r.Use(middleware.Recoverer)
|
||||||
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
r.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||||
q := qbitHandler{qbit: s.qbit, logger: s.logger}
|
logLevel := s.logger.GetLevel().String()
|
||||||
ui := uiHandler{qbit: s.qbit, logger: common.NewLogger("UI", os.Stdout)}
|
debug := logLevel == "debug"
|
||||||
|
q := qbitHandler{qbit: s.qbit, logger: s.logger, debug: debug}
|
||||||
|
ui := uiHandler{qbit: s.qbit, logger: common.NewLogger("UI", s.logger.GetLevel().String(), os.Stdout), debug: debug}
|
||||||
|
|
||||||
// Register routes
|
// Register routes
|
||||||
q.Routes(r)
|
q.Routes(r)
|
||||||
@@ -46,7 +46,7 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
|
|
||||||
go s.qbit.StartWorker(context.Background())
|
go s.qbit.StartWorker(context.Background())
|
||||||
|
|
||||||
s.logger.Printf("Starting QBit server on :%s", s.qbit.Port)
|
s.logger.Info().Msgf("Starting QBit server on :%s", s.qbit.Port)
|
||||||
port := fmt.Sprintf(":%s", s.qbit.Port)
|
port := fmt.Sprintf(":%s", s.qbit.Port)
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: port,
|
Addr: port,
|
||||||
@@ -58,12 +58,12 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
fmt.Printf("Error starting server: %v\n", err)
|
s.logger.Info().Msgf("Error starting server: %v", err)
|
||||||
stop()
|
stop()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
fmt.Println("Shutting down gracefully...")
|
s.logger.Info().Msg("Shutting down gracefully...")
|
||||||
return srv.Shutdown(context.Background())
|
return srv.Shutdown(context.Background())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,23 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form id="configForm">
|
<form id="configForm">
|
||||||
|
<div class="section mb-5">
|
||||||
|
<h5 class="border-bottom pb-2">General Configuration</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="qbitDebug">Log Level</label>
|
||||||
|
<select class="form-select" name="qbit.log_level" id="log-level" disabled>
|
||||||
|
<option value="info">Info</option>
|
||||||
|
<option value="debug">Debug</option>
|
||||||
|
<option value="warn">Warning</option>
|
||||||
|
<option value="error">Error</option>
|
||||||
|
<option value="trace">Trace</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Debrid Configuration -->
|
<!-- Debrid Configuration -->
|
||||||
<div class="section mb-5">
|
<div class="section mb-5">
|
||||||
<h5 class="border-bottom pb-2">Debrid Configuration</h5>
|
<h5 class="border-bottom pb-2">Debrid Configuration</h5>
|
||||||
@@ -37,9 +54,15 @@
|
|||||||
<input type="number" class="form-control" name="qbit.refresh_interval">
|
<input type="number" class="form-control" name="qbit.refresh_interval">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 mb-3">
|
<div class="col-12 mb-3">
|
||||||
<div class="form-check">
|
<div class="form-group">
|
||||||
<input type="checkbox" disabled class="form-check-input" name="qbit.debug" id="qbitDebug">
|
<label for="qbitDebug">Log Level</label>
|
||||||
<label class="form-check-label" for="qbitDebug">Enable Debug Mode</label>
|
<select class="form-select" name="qbit.log_level" id="qbitDebug" disabled>
|
||||||
|
<option value="info">Info</option>
|
||||||
|
<option value="debug">Debug</option>
|
||||||
|
<option value="warn">Warning</option>
|
||||||
|
<option value="error">Error</option>
|
||||||
|
<option value="trace">Trace</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,7 +165,6 @@
|
|||||||
fetch('/internal/config')
|
fetch('/internal/config')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(config => {
|
.then(config => {
|
||||||
console.log(config)
|
|
||||||
// Load Debrid configs
|
// Load Debrid configs
|
||||||
config.debrids?.forEach(debrid => {
|
config.debrids?.forEach(debrid => {
|
||||||
addDebridConfig(debrid);
|
addDebridConfig(debrid);
|
||||||
@@ -180,6 +202,12 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load general config
|
||||||
|
|
||||||
|
const logLevel = document.getElementById('log-level');
|
||||||
|
logLevel.value = config.log_level;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle form submission
|
// Handle form submission
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>DebridArr - {{.Title}}</title>
|
<title>DecyphArr - {{.Title}}</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" rel="stylesheet">
|
||||||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet"/>
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet"/>
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
<nav class="navbar navbar-expand-lg navbar-light mb-4">
|
<nav class="navbar navbar-expand-lg navbar-light mb-4">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">
|
<a class="navbar-brand" href="/">
|
||||||
<i class="bi bi-cloud-download me-2"></i>DebridArr
|
<i class="bi bi-cloud-download me-2"></i>DecyphArr
|
||||||
</a>
|
</a>
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
|
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/version"
|
"github.com/sirrobot01/debrid-blackhole/pkg/version"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -50,7 +50,7 @@ var content embed.FS
|
|||||||
|
|
||||||
type uiHandler struct {
|
type uiHandler struct {
|
||||||
qbit *shared.QBit
|
qbit *shared.QBit
|
||||||
logger *log.Logger
|
logger zerolog.Logger
|
||||||
debug bool
|
debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ func (u *uiHandler) handleRepairMedia(w http.ResponseWriter, r *http.Request) {
|
|||||||
go func() {
|
go func() {
|
||||||
err := a.Repair(tvId)
|
err := a.Repair(tvId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
u.logger.Printf("Failed to repair: %v", err)
|
u.logger.Info().Msgf("Failed to repair: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (q *QBit) processManualFiles(debridTorrent *debrid.Torrent) (string, error) {
|
func (q *QBit) processManualFiles(debridTorrent *debrid.Torrent) (string, error) {
|
||||||
q.logger.Printf("Downloading %d files...", len(debridTorrent.DownloadLinks))
|
q.logger.Info().Msgf("Downloading %d files...", len(debridTorrent.DownloadLinks))
|
||||||
torrentPath := common.RemoveExtension(debridTorrent.OriginalFilename)
|
torrentPath := common.RemoveExtension(debridTorrent.OriginalFilename)
|
||||||
parent := common.RemoveInvalidChars(filepath.Join(q.DownloadFolder, debridTorrent.Arr.Name, torrentPath))
|
parent := common.RemoveInvalidChars(filepath.Join(q.DownloadFolder, debridTorrent.Arr.Name, torrentPath))
|
||||||
err := os.MkdirAll(parent, os.ModePerm)
|
err := os.MkdirAll(parent, os.ModePerm)
|
||||||
@@ -30,7 +30,7 @@ func (q *QBit) downloadFiles(debridTorrent *debrid.Torrent, parent string) {
|
|||||||
client := downloaders.GetHTTPClient()
|
client := downloaders.GetHTTPClient()
|
||||||
for _, link := range debridTorrent.DownloadLinks {
|
for _, link := range debridTorrent.DownloadLinks {
|
||||||
if link.DownloadLink == "" {
|
if link.DownloadLink == "" {
|
||||||
q.logger.Printf("No download link found for %s\n", link.Filename)
|
q.logger.Info().Msgf("No download link found for %s", link.Filename)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
@@ -40,14 +40,14 @@ func (q *QBit) downloadFiles(debridTorrent *debrid.Torrent, parent string) {
|
|||||||
defer func() { <-semaphore }()
|
defer func() { <-semaphore }()
|
||||||
err := downloaders.NormalHTTP(client, link.DownloadLink, filepath.Join(parent, link.Filename))
|
err := downloaders.NormalHTTP(client, link.DownloadLink, filepath.Join(parent, link.Filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Error downloading %s: %v\n", link.DownloadLink, err)
|
q.logger.Info().Msgf("Error downloading %s: %v", link.DownloadLink, err)
|
||||||
} else {
|
} else {
|
||||||
q.logger.Printf("Downloaded %s successfully\n", link.DownloadLink)
|
q.logger.Info().Msgf("Downloaded %s successfully", link.DownloadLink)
|
||||||
}
|
}
|
||||||
}(link)
|
}(link)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
q.logger.Printf("Downloaded all files for %s\n", debridTorrent.Name)
|
q.logger.Info().Msgf("Downloaded all files for %s", debridTorrent.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *QBit) ProcessSymlink(debridTorrent *debrid.Torrent) (string, error) {
|
func (q *QBit) ProcessSymlink(debridTorrent *debrid.Torrent) (string, error) {
|
||||||
@@ -57,18 +57,25 @@ func (q *QBit) ProcessSymlink(debridTorrent *debrid.Torrent) (string, error) {
|
|||||||
if len(files) == 0 {
|
if len(files) == 0 {
|
||||||
return "", fmt.Errorf("no video files found")
|
return "", fmt.Errorf("no video files found")
|
||||||
}
|
}
|
||||||
q.logger.Printf("Checking %d files...", len(files))
|
q.logger.Info().Msgf("Checking %d files...", len(files))
|
||||||
rCloneBase := debridTorrent.Debrid.GetMountPath()
|
rCloneBase := debridTorrent.Debrid.GetMountPath()
|
||||||
torrentPath, err := q.getTorrentPath(rCloneBase, debridTorrent) // /MyTVShow/
|
torrentPath, err := q.getTorrentPath(rCloneBase, debridTorrent) // /MyTVShow/
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to get torrent path: %v", err)
|
return "", fmt.Errorf("failed to get torrent path: %v", err)
|
||||||
}
|
}
|
||||||
torrentSymlinkPath := filepath.Join(q.DownloadFolder, debridTorrent.Arr.Name, torrentPath) // /mnt/symlinks/{category}/MyTVShow/
|
// Fix for alldebrid
|
||||||
|
newTorrentPath := torrentPath
|
||||||
|
if newTorrentPath == "" {
|
||||||
|
// Alldebrid at times doesn't return the parent folder for single file torrents
|
||||||
|
newTorrentPath = common.RemoveExtension(debridTorrent.Name) // MyTVShow
|
||||||
|
}
|
||||||
|
torrentSymlinkPath := filepath.Join(q.DownloadFolder, debridTorrent.Arr.Name, newTorrentPath) // /mnt/symlinks/{category}/MyTVShow/
|
||||||
err = os.MkdirAll(torrentSymlinkPath, os.ModePerm)
|
err = os.MkdirAll(torrentSymlinkPath, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to create directory: %s: %v", torrentSymlinkPath, err)
|
return "", fmt.Errorf("failed to create directory: %s: %v", torrentSymlinkPath, err)
|
||||||
}
|
}
|
||||||
torrentRclonePath := filepath.Join(rCloneBase, torrentPath)
|
torrentRclonePath := filepath.Join(rCloneBase, torrentPath) // leave it as is
|
||||||
|
q.logger.Debug().Msgf("Debrid torrent path: %s\nSymlink Path: %s", torrentRclonePath, torrentSymlinkPath)
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go checkFileLoop(&wg, torrentRclonePath, file, ready)
|
go checkFileLoop(&wg, torrentRclonePath, file, ready)
|
||||||
@@ -80,7 +87,7 @@ func (q *QBit) ProcessSymlink(debridTorrent *debrid.Torrent) (string, error) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
for f := range ready {
|
for f := range ready {
|
||||||
q.logger.Println("File is ready:", f.Path)
|
q.logger.Info().Msgf("File is ready: %s", f.Path)
|
||||||
q.createSymLink(torrentSymlinkPath, torrentRclonePath, f)
|
q.createSymLink(torrentSymlinkPath, torrentRclonePath, f)
|
||||||
}
|
}
|
||||||
return torrentPath, nil
|
return torrentPath, nil
|
||||||
@@ -88,8 +95,10 @@ func (q *QBit) ProcessSymlink(debridTorrent *debrid.Torrent) (string, error) {
|
|||||||
|
|
||||||
func (q *QBit) getTorrentPath(rclonePath string, debridTorrent *debrid.Torrent) (string, error) {
|
func (q *QBit) getTorrentPath(rclonePath string, debridTorrent *debrid.Torrent) (string, error) {
|
||||||
for {
|
for {
|
||||||
|
q.logger.Debug().Msgf("Checking for torrent path: %s", rclonePath)
|
||||||
torrentPath, err := debridTorrent.GetMountFolder(rclonePath)
|
torrentPath, err := debridTorrent.GetMountFolder(rclonePath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
q.logger.Debug().Msgf("Found torrent path: %s", torrentPath)
|
||||||
return torrentPath, err
|
return torrentPath, err
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
@@ -104,10 +113,6 @@ func (q *QBit) createSymLink(path string, torrentMountPath string, file debrid.T
|
|||||||
torrentFilePath := filepath.Join(torrentMountPath, file.Name) // debridFolder/MyTVShow/MyTVShow.S01E01.720p.mkv
|
torrentFilePath := filepath.Join(torrentMountPath, file.Name) // debridFolder/MyTVShow/MyTVShow.S01E01.720p.mkv
|
||||||
err := os.Symlink(torrentFilePath, fullPath)
|
err := os.Symlink(torrentFilePath, fullPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
q.logger.Printf("Failed to create symlink: %s: %v\n", fullPath, err)
|
q.logger.Info().Msgf("Failed to create symlink: %s: %v", fullPath, err)
|
||||||
}
|
}
|
||||||
// Check if the file exists
|
|
||||||
//if !common.FileReady(fullPath) {
|
|
||||||
// q.logger.Printf("Symlink not ready: %s\n", fullPath)
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package shared
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
"github.com/sirrobot01/debrid-blackhole/common"
|
"github.com/sirrobot01/debrid-blackhole/common"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
|
||||||
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -18,12 +18,12 @@ type QBit struct {
|
|||||||
Debrid *debrid.DebridService
|
Debrid *debrid.DebridService
|
||||||
Storage *TorrentStorage
|
Storage *TorrentStorage
|
||||||
debug bool
|
debug bool
|
||||||
logger *log.Logger
|
logger zerolog.Logger
|
||||||
Arrs *arr.Storage
|
Arrs *arr.Storage
|
||||||
RefreshInterval int
|
RefreshInterval int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewQBit(config *common.Config, deb *debrid.DebridService, logger *log.Logger, arrs *arr.Storage) *QBit {
|
func NewQBit(config *common.Config, deb *debrid.DebridService, logger zerolog.Logger, arrs *arr.Storage) *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)
|
||||||
@@ -34,7 +34,6 @@ func NewQBit(config *common.Config, deb *debrid.DebridService, logger *log.Logge
|
|||||||
DownloadFolder: cfg.DownloadFolder,
|
DownloadFolder: cfg.DownloadFolder,
|
||||||
Categories: cfg.Categories,
|
Categories: cfg.Categories,
|
||||||
Debrid: deb,
|
Debrid: deb,
|
||||||
debug: cfg.Debug,
|
|
||||||
Storage: NewTorrentStorage("torrents.json"),
|
Storage: NewTorrentStorage("torrents.json"),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
Arrs: arrs,
|
Arrs: arrs,
|
||||||
|
|||||||
@@ -92,11 +92,11 @@ func (q *QBit) CreateTorrentFromMagnet(magnet *common.Magnet, category, source s
|
|||||||
func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr *arr.Arr, isSymlink bool) {
|
func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr *arr.Arr, isSymlink bool) {
|
||||||
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.Debug().Msgf("%s -> (%s) Download Progress: %.2f%%", debridTorrent.Debrid.GetName(), debridTorrent.Name, progress)
|
||||||
time.Sleep(4 * time.Second)
|
time.Sleep(10 * 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.Error().Msgf("Error checking status: %v", err)
|
||||||
go debridTorrent.Delete()
|
go debridTorrent.Delete()
|
||||||
q.MarkAsFailed(torrent)
|
q.MarkAsFailed(torrent)
|
||||||
_ = arr.Refresh()
|
_ = arr.Refresh()
|
||||||
@@ -118,7 +118,7 @@ func (q *QBit) ProcessFiles(torrent *Torrent, debridTorrent *debrid.Torrent, arr
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
q.MarkAsFailed(torrent)
|
q.MarkAsFailed(torrent)
|
||||||
go debridTorrent.Delete()
|
go debridTorrent.Delete()
|
||||||
q.logger.Printf("Error: %v", err)
|
q.logger.Info().Msgf("Error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
torrent.TorrentPath = filepath.Base(torrentPath)
|
torrent.TorrentPath = filepath.Base(torrentPath)
|
||||||
@@ -181,7 +181,7 @@ func (q *QBit) UpdateTorrent(t *Torrent, debridTorrent *debrid.Torrent) *Torrent
|
|||||||
debridTorrent, _ = db.GetTorrent(t.ID)
|
debridTorrent, _ = db.GetTorrent(t.ID)
|
||||||
}
|
}
|
||||||
if debridTorrent == nil {
|
if debridTorrent == nil {
|
||||||
q.logger.Printf("Torrent with ID %s not found in %s", t.ID, db.GetName())
|
q.logger.Info().Msgf("Torrent with ID %s not found in %s", t.ID, db.GetName())
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
if debridTorrent.Status != "downloaded" {
|
if debridTorrent.Status != "downloaded" {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (q *QBit) StartWorker(ctx context.Context) {
|
func (q *QBit) StartWorker(ctx context.Context) {
|
||||||
q.logger.Println("Qbit Worker started")
|
q.logger.Info().Msg("Qbit Worker started")
|
||||||
q.StartRefreshWorker(ctx)
|
q.StartRefreshWorker(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ func (q *QBit) StartRefreshWorker(ctx context.Context) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-refreshCtx.Done():
|
case <-refreshCtx.Done():
|
||||||
q.logger.Println("Qbit Refresh Worker stopped")
|
q.logger.Info().Msg("Qbit Refresh Worker stopped")
|
||||||
return
|
return
|
||||||
case <-refreshTicker.C:
|
case <-refreshTicker.C:
|
||||||
torrents := q.Storage.GetAll("", "", nil)
|
torrents := q.Storage.GetAll("", "", nil)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
func Start(ctx context.Context, config *common.Config, arrs *arr.Storage) error {
|
func Start(ctx context.Context, config *common.Config, arrs *arr.Storage) error {
|
||||||
ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
|
ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
|
||||||
logger := common.NewLogger("Repair", os.Stdout)
|
logger := common.NewLogger("Repair", config.LogLevel, os.Stdout)
|
||||||
defer stop()
|
defer stop()
|
||||||
|
|
||||||
duration, err := parseSchedule(config.Repair.Interval)
|
duration, err := parseSchedule(config.Repair.Interval)
|
||||||
@@ -23,7 +23,7 @@ func Start(ctx context.Context, config *common.Config, arrs *arr.Storage) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.Repair.RunOnStart {
|
if config.Repair.RunOnStart {
|
||||||
logger.Printf("Running initial repair")
|
logger.Info().Msgf("Running initial repair")
|
||||||
if err := repair(arrs); err != nil {
|
if err := repair(arrs); err != nil {
|
||||||
log.Printf("Error during initial repair: %v", err)
|
log.Printf("Error during initial repair: %v", err)
|
||||||
return err
|
return err
|
||||||
@@ -34,20 +34,20 @@ func Start(ctx context.Context, config *common.Config, arrs *arr.Storage) error
|
|||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
if strings.Contains(config.Repair.Interval, ":") {
|
if strings.Contains(config.Repair.Interval, ":") {
|
||||||
logger.Printf("Starting repair worker, scheduled daily at %s", config.Repair.Interval)
|
logger.Info().Msgf("Starting repair worker, scheduled daily at %s", config.Repair.Interval)
|
||||||
} else {
|
} else {
|
||||||
logger.Printf("Starting repair worker with %v interval", duration)
|
logger.Info().Msgf("Starting repair worker with %v interval", duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
logger.Println("Repair worker stopped")
|
logger.Info().Msg("Repair worker stopped")
|
||||||
return nil
|
return nil
|
||||||
case t := <-ticker.C:
|
case t := <-ticker.C:
|
||||||
logger.Printf("Running repair at %v", t.Format("15:04:05"))
|
logger.Info().Msgf("Running repair at %v", t.Format("15:04:05"))
|
||||||
if err := repair(arrs); err != nil {
|
if err := repair(arrs); err != nil {
|
||||||
logger.Printf("Error during repair: %v", err)
|
logger.Info().Msgf("Error during repair: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ func Start(ctx context.Context, config *common.Config, arrs *arr.Storage) error
|
|||||||
if strings.Contains(config.Repair.Interval, ":") {
|
if strings.Contains(config.Repair.Interval, ":") {
|
||||||
nextDuration, err := parseSchedule(config.Repair.Interval)
|
nextDuration, err := parseSchedule(config.Repair.Interval)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Printf("Error calculating next schedule: %v", err)
|
logger.Info().Msgf("Error calculating next schedule: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ticker.Reset(nextDuration)
|
ticker.Reset(nextDuration)
|
||||||
|
|||||||
Regular → Executable
-1
@@ -46,7 +46,6 @@ echo "Deploying version $VERSION to $BRANCH branch..."
|
|||||||
|
|
||||||
# Ensure we're on the right branch
|
# Ensure we're on the right branch
|
||||||
git checkout $BRANCH || exit 1
|
git checkout $BRANCH || exit 1
|
||||||
git pull origin $BRANCH || exit 1
|
|
||||||
|
|
||||||
# Create and push tag
|
# Create and push tag
|
||||||
echo "Creating tag $TAG..."
|
echo "Creating tag $TAG..."
|
||||||
|
|||||||
Reference in New Issue
Block a user