fix(lint): use default:none to disable errcheck, fix all gofmt and exhaustive
This commit is contained in:
parent
4426219f35
commit
aed5f0475d
24 changed files with 74 additions and 77 deletions
|
|
@ -4,6 +4,7 @@ run:
|
|||
timeout: 5m
|
||||
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- govet
|
||||
- ineffassign
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ func TestWSTransportConnectAndAuth(t *testing.T) {
|
|||
|
||||
// Send registered response
|
||||
conn.WriteJSON(wsRegisteredMessage{
|
||||
Type: "registered",
|
||||
User: UserInfo{Name: "WS User", Plan: "pro", IsPro: true},
|
||||
Type: "registered",
|
||||
User: UserInfo{Name: "WS User", Plan: "pro", IsPro: true},
|
||||
Features: FeatureFlags{Torrent: true},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ type Task struct {
|
|||
Title string `json:"title"`
|
||||
ContentID *int `json:"contentId,omitempty"`
|
||||
IMDbID string `json:"imdbId,omitempty"`
|
||||
PreferredMethod string `json:"preferredMethod"` // auto | debrid | usenet | torrent
|
||||
Mode string `json:"mode,omitempty"` // download | stream
|
||||
PreferredMethod string `json:"preferredMethod"` // auto | debrid | usenet | torrent
|
||||
Mode string `json:"mode,omitempty"` // download | stream
|
||||
DirectURL string `json:"directUrl,omitempty"` // HTTPS download URL (debrid, etc.)
|
||||
DirectFileName string `json:"directFileName,omitempty"` // Original filename from direct URL
|
||||
NzbID string `json:"nzbId,omitempty"` // Pre-resolved NZB ID from server
|
||||
|
|
@ -88,8 +88,8 @@ type StreamRequest struct {
|
|||
// StatusUpdate is sent by the CLI to report download progress.
|
||||
type StatusUpdate struct {
|
||||
TaskID string `json:"taskId"`
|
||||
Status string `json:"status,omitempty"` // downloading | completed | failed
|
||||
Progress int `json:"progress,omitempty"` // 0-100
|
||||
Status string `json:"status,omitempty"` // downloading | completed | failed
|
||||
Progress int `json:"progress,omitempty"` // 0-100
|
||||
DownloadedBytes int64 `json:"downloadedBytes,omitempty"`
|
||||
TotalBytes int64 `json:"totalBytes,omitempty"`
|
||||
SpeedBps int64 `json:"speedBps,omitempty"`
|
||||
|
|
@ -249,9 +249,9 @@ type ConfigureDebridRequest struct {
|
|||
|
||||
// ConfigureDebridResponse is returned after configuring a debrid provider.
|
||||
type ConfigureDebridResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Success bool `json:"success"`
|
||||
Account DebridAccount `json:"account"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// DebridAccount holds verified debrid account info.
|
||||
|
|
|
|||
|
|
@ -11,16 +11,16 @@ import (
|
|||
|
||||
// Client talks to a single *arr instance (Sonarr, Radarr, or Prowlarr).
|
||||
type Client struct {
|
||||
baseURL string
|
||||
apiKey string
|
||||
baseURL string
|
||||
apiKey string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewClient creates a client for the given *arr instance.
|
||||
func NewClient(baseURL, apiKey string) *Client {
|
||||
return &Client{
|
||||
baseURL: strings.TrimRight(baseURL, "/"),
|
||||
apiKey: apiKey,
|
||||
baseURL: strings.TrimRight(baseURL, "/"),
|
||||
apiKey: apiKey,
|
||||
httpClient: &http.Client{Timeout: 15 * time.Second},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ func TestExtractBlocklistedHashes(t *testing.T) {
|
|||
{Data: BlocklistData{InfoHash: "AAAA"}},
|
||||
{Data: BlocklistData{InfoHash: "AAAA"}}, // duplicate
|
||||
{Data: BlocklistData{InfoHash: "BBBB"}},
|
||||
{Data: BlocklistData{InfoHash: ""}}, // empty
|
||||
{Data: BlocklistData{InfoHash: ""}}, // empty
|
||||
}
|
||||
hashes := ExtractBlocklistedHashes(items)
|
||||
if len(hashes) != 2 {
|
||||
|
|
@ -139,8 +139,8 @@ func TestExtractBlocklistedHashes(t *testing.T) {
|
|||
func TestExtractDownloadedHashes(t *testing.T) {
|
||||
records := []HistoryRecord{
|
||||
{EventType: "downloadFolderImported", Data: HistoryData{InfoHash: "hash1"}},
|
||||
{EventType: "grabbed", Data: HistoryData{InfoHash: "hash2"}}, // not imported
|
||||
{EventType: "downloadFolderImported", Data: HistoryData{InfoHash: "hash1"}}, // duplicate
|
||||
{EventType: "grabbed", Data: HistoryData{InfoHash: "hash2"}}, // not imported
|
||||
{EventType: "downloadFolderImported", Data: HistoryData{InfoHash: "hash1"}}, // duplicate
|
||||
{EventType: "downloadFolderImported", Data: HistoryData{InfoHash: "hash3"}},
|
||||
}
|
||||
hashes := ExtractDownloadedHashes(records)
|
||||
|
|
|
|||
|
|
@ -112,11 +112,11 @@ type Tag struct {
|
|||
|
||||
// HistoryRecord is a single entry from /api/v3/history.
|
||||
type HistoryRecord struct {
|
||||
ID int `json:"id"`
|
||||
EventType string `json:"eventType"` // "grabbed", "downloadFolderImported", etc.
|
||||
DownloadID string `json:"downloadId"`
|
||||
SourceTitle string `json:"sourceTitle"`
|
||||
Data HistoryData `json:"data"`
|
||||
ID int `json:"id"`
|
||||
EventType string `json:"eventType"` // "grabbed", "downloadFolderImported", etc.
|
||||
DownloadID string `json:"downloadId"`
|
||||
SourceTitle string `json:"sourceTitle"`
|
||||
Data HistoryData `json:"data"`
|
||||
}
|
||||
|
||||
// HistoryData holds the nested data of a history record.
|
||||
|
|
@ -127,14 +127,14 @@ type HistoryData struct {
|
|||
|
||||
// HistoryResponse wraps the paginated history from *arr.
|
||||
type HistoryResponse struct {
|
||||
Records []HistoryRecord `json:"records"`
|
||||
TotalRecords int `json:"totalRecords"`
|
||||
Records []HistoryRecord `json:"records"`
|
||||
TotalRecords int `json:"totalRecords"`
|
||||
}
|
||||
|
||||
// BlocklistItem is an item the user explicitly rejected.
|
||||
type BlocklistItem struct {
|
||||
ID int `json:"id"`
|
||||
SourceTitle string `json:"sourceTitle"`
|
||||
ID int `json:"id"`
|
||||
SourceTitle string `json:"sourceTitle"`
|
||||
Data BlocklistData `json:"data"`
|
||||
}
|
||||
|
||||
|
|
@ -145,8 +145,8 @@ type BlocklistData struct {
|
|||
|
||||
// BlocklistResponse wraps paginated blocklist from *arr.
|
||||
type BlocklistResponse struct {
|
||||
Records []BlocklistItem `json:"records"`
|
||||
TotalRecords int `json:"totalRecords"`
|
||||
Records []BlocklistItem `json:"records"`
|
||||
TotalRecords int `json:"totalRecords"`
|
||||
}
|
||||
|
||||
// Instance represents a discovered *arr application.
|
||||
|
|
|
|||
|
|
@ -341,4 +341,3 @@ func CleanableBytes() int64 {
|
|||
|
||||
return total
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ func TestFileSize_NonExistent(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
func TestRunClean_DryRun(t *testing.T) {
|
||||
err := runClean(true, false, false)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ var configCategories = []string{"downloads", "organization", "notifications", "d
|
|||
|
||||
func newConfigCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "config [category]",
|
||||
Short: "Edit settings interactively",
|
||||
Use: "config [category]",
|
||||
Short: "Edit settings interactively",
|
||||
Long: `Edit unarr settings interactively with a category-based menu.
|
||||
|
||||
Categories:
|
||||
|
|
|
|||
|
|
@ -236,4 +236,3 @@ func runDaemonUninstall() error {
|
|||
fmt.Println()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import (
|
|||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
tc "github.com/torrentclaw/go-client"
|
||||
"github.com/torrentclaw/unarr/internal/config"
|
||||
"github.com/torrentclaw/unarr/internal/sentry"
|
||||
tc "github.com/torrentclaw/go-client"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -155,4 +155,3 @@ func handleStreamTask(parentCtx context.Context, at agent.Task, reporter *engine
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ import (
|
|||
"github.com/anacrolix/torrent"
|
||||
)
|
||||
|
||||
|
||||
|
||||
// StreamConfig holds settings for the streaming engine.
|
||||
type StreamConfig struct {
|
||||
DataDir string
|
||||
|
|
@ -30,7 +28,7 @@ type StreamConfig struct {
|
|||
type StreamStatus int
|
||||
|
||||
const (
|
||||
StreamStatusMetadata StreamStatus = iota
|
||||
StreamStatusMetadata StreamStatus = iota
|
||||
StreamStatusBuffering
|
||||
StreamStatusReady
|
||||
StreamStatusError
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ type responseRecorder struct {
|
|||
body *strings.Builder
|
||||
}
|
||||
|
||||
func (r *responseRecorder) Header() http.Header { return r.headers }
|
||||
func (r *responseRecorder) Header() http.Header { return r.headers }
|
||||
func (r *responseRecorder) WriteHeader(code int) { r.statusCode = code }
|
||||
func (r *responseRecorder) Write(b []byte) (int, error) {
|
||||
if r.statusCode == 0 {
|
||||
|
|
|
|||
|
|
@ -191,6 +191,8 @@ func (t *Task) ToStatusUpdate() agent.StatusUpdate {
|
|||
apiStatus = "completed"
|
||||
case StatusFailed:
|
||||
apiStatus = "failed"
|
||||
default:
|
||||
// StatusPending, StatusClaimed, StatusCancelled — not reported
|
||||
}
|
||||
|
||||
return agent.StatusUpdate{
|
||||
|
|
|
|||
|
|
@ -173,8 +173,8 @@ func TestToStatusUpdate(t *testing.T) {
|
|||
|
||||
func TestToStatusUpdateGranularStates(t *testing.T) {
|
||||
tests := []struct {
|
||||
status TaskStatus
|
||||
wantAPI string
|
||||
status TaskStatus
|
||||
wantAPI string
|
||||
}{
|
||||
{StatusResolving, "resolving"},
|
||||
{StatusDownloading, "downloading"},
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
alog "github.com/anacrolix/log"
|
||||
"github.com/anacrolix/dht/v2"
|
||||
"github.com/anacrolix/dht/v2/krpc"
|
||||
alog "github.com/anacrolix/log"
|
||||
"github.com/anacrolix/torrent"
|
||||
"github.com/anacrolix/torrent/storage"
|
||||
"github.com/torrentclaw/unarr/internal/config"
|
||||
|
|
@ -60,16 +60,16 @@ var defaultTrackers = []string{
|
|||
|
||||
// TorrentConfig holds settings for the BitTorrent downloader.
|
||||
type TorrentConfig struct {
|
||||
DataDir string
|
||||
MetadataTimeout time.Duration // how long to wait for torrent metadata (default 15m, 0 = unlimited)
|
||||
StallTimeout time.Duration // no progress during download for this long = stall (default 10m)
|
||||
MaxTimeout time.Duration // absolute maximum per torrent (default 0 = unlimited)
|
||||
MaxDownloadRate int64 // bytes/s, 0 = unlimited
|
||||
MaxUploadRate int64 // bytes/s, 0 = unlimited
|
||||
ListenPort int // fixed port for incoming peers (default 42069, 0 = random)
|
||||
SeedEnabled bool
|
||||
SeedRatio float64 // target seed ratio (default 0, meaning seed until SeedTime)
|
||||
SeedTime time.Duration // min seed time after completion (default 0)
|
||||
DataDir string
|
||||
MetadataTimeout time.Duration // how long to wait for torrent metadata (default 15m, 0 = unlimited)
|
||||
StallTimeout time.Duration // no progress during download for this long = stall (default 10m)
|
||||
MaxTimeout time.Duration // absolute maximum per torrent (default 0 = unlimited)
|
||||
MaxDownloadRate int64 // bytes/s, 0 = unlimited
|
||||
MaxUploadRate int64 // bytes/s, 0 = unlimited
|
||||
ListenPort int // fixed port for incoming peers (default 42069, 0 = random)
|
||||
SeedEnabled bool
|
||||
SeedRatio float64 // target seed ratio (default 0, meaning seed until SeedTime)
|
||||
SeedTime time.Duration // min seed time after completion (default 0)
|
||||
}
|
||||
|
||||
// TorrentDownloader downloads torrents via BitTorrent P2P.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
// activeDownload holds the state for a single in-progress usenet download.
|
||||
type activeDownload struct {
|
||||
cancel context.CancelFunc
|
||||
taskDir string // populated after MkdirAll; empty before
|
||||
taskDir string // populated after MkdirAll; empty before
|
||||
tracker *download.ProgressTracker // populated after tracker creation; nil before
|
||||
}
|
||||
|
||||
|
|
@ -471,4 +471,3 @@ func sanitizeDir(name string) string {
|
|||
}
|
||||
return name
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ type MediaInfo struct {
|
|||
|
||||
// VideoInfo represents the primary video stream metadata.
|
||||
type VideoInfo struct {
|
||||
Codec string `json:"codec"` // "hevc", "h264", "av1"
|
||||
Codec string `json:"codec"` // "hevc", "h264", "av1"
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
BitDepth int `json:"bitDepth"` // 8, 10, 12
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
seasonRegex = regexp.MustCompile(`(?i)S(\d{1,2})E(\d{1,2})`)
|
||||
seasonOnly = regexp.MustCompile(`(?i)S(\d{1,2})(?:\b|$)`)
|
||||
altEpRegex = regexp.MustCompile(`(?i)(\d{1,2})x(\d{2})`)
|
||||
seasonRegex = regexp.MustCompile(`(?i)S(\d{1,2})E(\d{1,2})`)
|
||||
seasonOnly = regexp.MustCompile(`(?i)S(\d{1,2})(?:\b|$)`)
|
||||
altEpRegex = regexp.MustCompile(`(?i)(\d{1,2})x(\d{2})`)
|
||||
)
|
||||
|
||||
// ResolveResolution maps a pixel height to a standard resolution label.
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ import "github.com/torrentclaw/unarr/internal/library/mediainfo"
|
|||
|
||||
// LibraryItem represents a single scanned media file.
|
||||
type LibraryItem struct {
|
||||
FilePath string `json:"filePath"`
|
||||
FileName string `json:"fileName"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
ModTime string `json:"modTime"` // ISO 8601
|
||||
Title string `json:"title"`
|
||||
Year string `json:"year,omitempty"`
|
||||
Season int `json:"season,omitempty"`
|
||||
Episode int `json:"episode,omitempty"`
|
||||
Quality string `json:"quality,omitempty"` // "1080p" etc (from filename)
|
||||
Codec string `json:"codec,omitempty"` // "x265" etc (from filename)
|
||||
FilePath string `json:"filePath"`
|
||||
FileName string `json:"fileName"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
ModTime string `json:"modTime"` // ISO 8601
|
||||
Title string `json:"title"`
|
||||
Year string `json:"year,omitempty"`
|
||||
Season int `json:"season,omitempty"`
|
||||
Episode int `json:"episode,omitempty"`
|
||||
Quality string `json:"quality,omitempty"` // "1080p" etc (from filename)
|
||||
Codec string `json:"codec,omitempty"` // "x265" etc (from filename)
|
||||
MediaInfo *mediainfo.MediaInfo `json:"mediaInfo,omitempty"`
|
||||
ScanError string `json:"scanError,omitempty"`
|
||||
ScanError string `json:"scanError,omitempty"`
|
||||
}
|
||||
|
||||
// LibraryCache is the on-disk cache of scanned library items.
|
||||
|
|
|
|||
|
|
@ -161,5 +161,5 @@ func TestFormatContentType(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
func intPtr(v int) *int { return &v }
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
func intPtr(v int) *int { return &v }
|
||||
|
|
|
|||
|
|
@ -50,11 +50,11 @@ type xmlMeta struct {
|
|||
}
|
||||
|
||||
type xmlFile struct {
|
||||
Poster string `xml:"poster,attr"`
|
||||
Date string `xml:"date,attr"`
|
||||
Subject string `xml:"subject,attr"`
|
||||
Groups xmlGroups `xml:"groups"`
|
||||
Segments xmlSegments `xml:"segments"`
|
||||
Poster string `xml:"poster,attr"`
|
||||
Date string `xml:"date,attr"`
|
||||
Subject string `xml:"subject,attr"`
|
||||
Groups xmlGroups `xml:"groups"`
|
||||
Segments xmlSegments `xml:"segments"`
|
||||
}
|
||||
|
||||
type xmlGroups struct {
|
||||
|
|
@ -263,8 +263,9 @@ func (f *File) TotalBytes() int64 {
|
|||
|
||||
// subjectFilenameRe matches the filename in a typical Usenet subject line.
|
||||
// Examples:
|
||||
// "Movie.2024.1080p.mkv" yEnc (1/50)
|
||||
// [PRiVATE]-[#a]- "file.rar" yEnc (01/99)
|
||||
//
|
||||
// "Movie.2024.1080p.mkv" yEnc (1/50)
|
||||
// [PRiVATE]-[#a]- "file.rar" yEnc (01/99)
|
||||
var subjectFilenameRe = regexp.MustCompile(`"([^"]+)"`)
|
||||
|
||||
// Filename extracts the filename from the subject line.
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func IsPasswordProtected(archivePath string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
switch extType {
|
||||
switch extType { //nolint:exhaustive // ExtractorNone handled above
|
||||
case ExtractorUnrar:
|
||||
cmd := exec.Command(extPath, "t", "-p-", archivePath)
|
||||
output, err := cmd.CombinedOutput()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue