Features:

- Add file logging, server
- Fix minor repair bug
- Wrap up beta
This commit is contained in:
Mukhtar Akere
2025-01-23 00:27:12 +01:00
parent cfb0051b04
commit 74a55149fc
13 changed files with 113 additions and 11 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ docker-compose.yml
dist/
tmp/**
torrents.json
logs/**

View File

@@ -117,7 +117,10 @@
- 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
- Fix files with no parent directory
- Logging
- Add a more robust logging system
- Add logging to a file
- Add logging to the UI

View File

@@ -21,8 +21,9 @@ FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /blackhole /blackhole
COPY --from=builder /app/README.md /README.md
ENV LOG_PATH=/app/logs
EXPOSE 8181
EXPOSE 8181 8282
VOLUME ["/app"]

View File

@@ -4,6 +4,27 @@
This is a Golang implementation go Torrent QbitTorrent with a **Multiple Debrid service support**.
### Table of Contents
- [Features](#features)
- [Supported Debrid Providers](#supported-debrid-providers)
- [Installation](#installation)
- [Docker Compose](#docker-compose)
- [Binary](#binary)
- [Usage](#usage)
- [Connecting to Sonarr/Radarr](#connecting-to-sonarrradarr)
- [Sample Config](#sample-config)
- [Config Notes](#config-notes)
- [Log Level](#log-level)
- [Max Cache Size](#max-cache-size)
- [Debrid Config](#debrid-config)
- [Proxy Config](#proxy-config)
- [Qbittorrent Config](#qbittorrent-config)
- [Arrs Config](#arrs-config)
- [Proxy](#proxy)
- [Repair Worker](#repair-worker)
- [Changelog](#changelog)
- [TODO](#todo)
### Features
@@ -25,7 +46,8 @@ The proxy is useful in filtering out un-cached Real Debrid torrents
- [All Debrid](https://alldebrid.com)
#### Installation
### Installation
##### Docker Compose
```yaml
version: '3.7'
@@ -38,7 +60,7 @@ services:
- "8181:8181" # Proxy
user: "1000:1000"
volumes:
- ./logs:/app/logs
- ./logs/:/app/logs
- /mnt/:/mnt
- ~/plex/configs/blackhole/config.json:/app/config.json # Config file, see below
environment:

View File

@@ -3,12 +3,37 @@ package common
import (
"fmt"
"github.com/rs/zerolog"
"gopkg.in/natefinch/lumberjack.v2"
"os"
"path/filepath"
"strings"
)
func GetLogPath() string {
logsDir := os.Getenv("LOG_PATH")
if logsDir == "" {
// Create the logs directory if it doesn't exist
logsDir = "logs"
}
if err := os.MkdirAll(logsDir, 0755); err != nil {
panic(fmt.Sprintf("Failed to create logs directory: %v", err))
}
return filepath.Join(logsDir, "decypharr.log")
}
func NewLogger(prefix string, level string, output *os.File) zerolog.Logger {
writer := zerolog.ConsoleWriter{
rotatingLogFile := &lumberjack.Logger{
Filename: GetLogPath(),
MaxSize: 10,
MaxBackups: 2,
MaxAge: 28,
Compress: true,
}
consoleWriter := zerolog.ConsoleWriter{
Out: output,
TimeFormat: "2006-01-02 15:04:05",
NoColor: false, // Set to true if you don't want colors
@@ -20,7 +45,21 @@ func NewLogger(prefix string, level string, output *os.File) zerolog.Logger {
},
}
logger := zerolog.New(writer).
fileWriter := zerolog.ConsoleWriter{
Out: rotatingLogFile,
TimeFormat: "2006-01-02 15:04:05",
NoColor: true, // No colors in file output
FormatLevel: func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("| %-6s|", i))
},
FormatMessage: func(i interface{}) string {
return fmt.Sprintf("[%s] %v", prefix, i)
},
}
multi := zerolog.MultiLevelWriter(consoleWriter, fileWriter)
logger := zerolog.New(multi).
With().
Timestamp().
Logger().

1
go.mod
View File

@@ -29,4 +29,5 @@ require (
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
)

2
go.sum
View File

@@ -288,6 +288,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -45,9 +45,6 @@ func (q *qbitHandler) Routes(r chi.Router) http.Handler {
func (u *uiHandler) Routes(r chi.Router) http.Handler {
r.Group(func(r chi.Router) {
//if u.debug {
// r.Use(middleware.Logger)
//}
r.Get("/", u.IndexHandler)
r.Get("/download", u.DownloadHandler)
r.Get("/repair", u.RepairHandler)

View File

@@ -11,6 +11,7 @@ import (
"github.com/sirrobot01/debrid-blackhole/pkg/arr"
"github.com/sirrobot01/debrid-blackhole/pkg/debrid"
"github.com/sirrobot01/debrid-blackhole/pkg/qbit/shared"
"io"
"net/http"
"os"
"os/signal"
@@ -41,6 +42,7 @@ func (s *Server) Start(ctx context.Context) error {
ui := uiHandler{qbit: s.qbit, logger: common.NewLogger("UI", s.logger.GetLevel().String(), os.Stdout), debug: debug}
// Register routes
r.Get("/logs", s.GetLogs)
q.Routes(r)
ui.Routes(r)
@@ -67,3 +69,29 @@ func (s *Server) Start(ctx context.Context) error {
s.logger.Info().Msg("Shutting down gracefully...")
return srv.Shutdown(context.Background())
}
func (s *Server) GetLogs(w http.ResponseWriter, r *http.Request) {
logFile := common.GetLogPath()
// Open and read the file
file, err := os.Open(logFile)
if err != nil {
http.Error(w, "Error reading log file", http.StatusInternalServerError)
return
}
defer file.Close()
// Set headers
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("Content-Disposition", "inline; filename=application.log")
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
// Stream the file
_, err = io.Copy(w, file)
if err != nil {
http.Error(w, "Error streaming log file", http.StatusInternalServerError)
return
}
}

View File

@@ -22,12 +22,12 @@
<th>Progress</th>
<th>Speed</th>
<th>Category</th>
<th>Debrid</th>
<th>State</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="torrentsList">
<!-- Will be populated by JavaScript -->
</tbody>
</table>
</div>
@@ -51,6 +51,7 @@
</td>
<td>${formatSpeed(torrent.dlspeed)}</td>
<td><span class="badge bg-secondary">${torrent.category || 'None'}</span></td>
<td><span class="badge bg-secondary">${torrent.debrid || 'None'}</span></td>
<td><span class="badge ${getStateColor(torrent.state)}">${torrent.state}</span></td>
<td>
<button class="btn btn-sm btn-outline-danger" onclick="deleteTorrent('${torrent.hash}')">

View File

@@ -87,6 +87,11 @@
<i class="bi bi-gear me-1"></i>Config
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/logs" target="_blank">
<i class="bi bi-journal me-1"></i>Logs
</a>
</li>
</ul>
<div class="d-flex align-items-center">
<span class="badge me-2" id="channel-badge">Loading...</span>

View File

@@ -171,6 +171,7 @@ type TorrentCategory struct {
type Torrent struct {
ID string `json:"-"`
DebridTorrent *debrid.Torrent `json:"-"`
Debrid string `json:"debrid"`
TorrentPath string `json:"-"`
AddedOn int64 `json:"added_on,omitempty"`

View File

@@ -158,6 +158,7 @@ func (q *QBit) UpdateTorrentMin(t *Torrent, debridTorrent *debrid.Torrent) *Torr
t.Name = debridTorrent.Name
t.AddedOn = addedOn.Unix()
t.DebridTorrent = debridTorrent
t.Debrid = debridTorrent.Debrid.GetName()
t.Size = totalSize
t.Completed = sizeCompleted
t.Downloaded = sizeCompleted