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