fix(filters): RED and OPS lossless parsing and filtering (#1373)

* fix(filters): RED and OPS lossless parsing and filtering

* fix(filters): logscore and EP parsing

* fix(filters): tests

* fix(filters): tests

* feat(definitions): RED parse title variable

* feat(indexers): setup indexer to filter tests

* feat(indexers): tests and improve parsing

* feat(indexers): improve tests
This commit is contained in:
ze0s 2024-01-28 22:03:25 +01:00 committed by GitHub
parent 9db5a8b116
commit 5328078b32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 1093 additions and 360 deletions

View file

@ -475,7 +475,7 @@ func (f *Filter) CheckFilter(r *Release) ([]string, bool) {
f.addRejectionF("formats not matching. got: %v want: %v", r.Audio, f.Formats)
}
if len(f.Quality) > 0 && !sliceContainsSlice(r.Audio, f.Quality) {
if len(f.Quality) > 0 && !containsMatchBasic(r.Audio, f.Quality) {
f.addRejectionF("quality not matching. got: %v want: %v", r.Audio, f.Quality)
}
@ -547,7 +547,7 @@ func (f *Filter) CheckFilter(r *Release) ([]string, bool) {
return nil, true
}
func (f Filter) checkMaxDownloads() bool {
func (f *Filter) checkMaxDownloads() bool {
if f.Downloads == nil {
return false
}
@ -580,7 +580,7 @@ func (f *Filter) isPerfectFLAC(r *Release) bool {
if !containsAny(r.Audio, "Log") {
return false
}
if !containsAny(r.Audio, "Log100") {
if !containsAny(r.Audio, "Log100") || r.LogScore != 100 {
return false
}
if !containsAny(r.Audio, "FLAC") {
@ -616,6 +616,32 @@ func (f *Filter) checkSizeFilter(r *Release) bool {
return true
}
// IsPerfectFLAC Perfect is "CD FLAC Cue Log 100% Lossless or 24bit Lossless"
func (f *Filter) IsPerfectFLAC(r *Release) ([]string, bool) {
rejections := []string{}
if r.Source != "CD" {
rejections = append(rejections, fmt.Sprintf("wanted Source CD, got %s", r.Source))
}
if r.AudioFormat != "FLAC" {
rejections = append(rejections, fmt.Sprintf("wanted Format FLAC, got %s", r.AudioFormat))
}
if !r.HasCue {
rejections = append(rejections, fmt.Sprintf("wanted Cue, got %t", r.HasCue))
}
if !r.HasLog {
rejections = append(rejections, fmt.Sprintf("wanted Log, got %t", r.HasLog))
}
if r.LogScore != 100 {
rejections = append(rejections, fmt.Sprintf("wanted Log Score 100, got %d", r.LogScore))
}
if !containsSlice(r.Bitrate, []string{"Lossless", "24bit Lossless"}) {
rejections = append(rejections, fmt.Sprintf("wanted Bitrate Lossless / 24bit Lossless, got %s", r.Bitrate))
}
return rejections, len(rejections) == 0
}
func (f *Filter) addRejection(reason string) {
f.Rejections = append(f.Rejections, reason)
}

View file

@ -1165,16 +1165,17 @@ func TestFilter_CheckFilter(t *testing.T) {
LogScore: 100,
Cue: true,
},
rejections: []string{"quality not matching. got: [FLAC Lossless Log100 Log] want: [24bit Lossless]", "wanted: cue", "log score. got: 0 want: 100"},
rejections: []string{"quality not matching. got: [FLAC Lossless Log100 Log] want: [24bit Lossless]", "wanted: cue"},
},
want: false,
},
{
name: "match_music_5",
fields: &Release{
TorrentName: "Artist - Albumname FLAC CD",
//TorrentName: "Artist - Albumname FLAC CD",
TorrentName: "Artist - Albumname [2022] [Album] (FLAC 24bit Lossless CD)",
Year: 2022,
ReleaseTags: "FLAC / Lossless / Log / 100% / Cue / CD",
ReleaseTags: "FLAC / 24bit Lossless / Log / 100% / Cue / CD",
Category: "Album",
},
args: args{
@ -1185,11 +1186,12 @@ func TestFilter_CheckFilter(t *testing.T) {
Artists: "Artist",
Media: []string{"CD"},
Formats: []string{"FLAC"},
Quality: []string{"24bit Lossless", "Lossless"},
PerfectFlac: true,
Log: true,
Quality: []string{"24bit Lossless"},
//PerfectFlac: true,
//Log: true,
//LogScore: 100,
Cue: true,
//Cue: true,
},
},
want: true,
@ -1214,7 +1216,7 @@ func TestFilter_CheckFilter(t *testing.T) {
LogScore: 100,
Cue: true,
},
rejections: []string{"release type not matching. got: Album want: [Single]", "log score. got: 0 want: 100"},
rejections: []string{"release type not matching. got: Album want: [Single]"},
},
want: false,
},
@ -1238,7 +1240,7 @@ func TestFilter_CheckFilter(t *testing.T) {
LogScore: 100,
Cue: true,
},
rejections: []string{"artists not matching. got: Artist want: Artiiiist", "log score. got: 0 want: 100"},
rejections: []string{"artists not matching. got: Artist want: Artiiiist"},
},
want: false,
},
@ -1266,6 +1268,28 @@ func TestFilter_CheckFilter(t *testing.T) {
},
want: true,
},
{
name: "match_music_9",
fields: &Release{
TorrentName: "Artist - Albumname [2022] [Album] (FLAC 24bit Lossless CD)",
Year: 2022,
ReleaseTags: "FLAC / 24bit Lossless / Log / 100% / Cue / CD",
Category: "Album",
},
args: args{
filter: Filter{
Enabled: true,
MatchReleaseTypes: []string{"Album"},
Years: "2020-2022",
Artists: "Artist",
Media: []string{"CD"},
Formats: []string{"FLAC"},
Quality: []string{"Lossless"},
},
rejections: []string{"quality not matching. got: [24BIT Lossless Cue FLAC Log100 Log] want: [Lossless]"},
},
want: false,
},
{
name: "match_anime_1",
fields: &Release{
@ -2130,8 +2154,8 @@ func Test_matchRegex(t *testing.T) {
{name: "test_5", args: args{tag: "Some.show.S01.DV.2160p.ATVP.WEB-DL.DDPA5.1.x265-GROUP2", filter: ".*1080p.+(group1|group3),.*720p.+,"}, want: false},
{name: "test_6", args: args{tag: "[Group] -Name of a Novel Something Good- [2012][Translated (Group)][EPUB]", filter: "(?:.*Something Good.*|.*Something Bad.*)"}, want: true},
{name: "test_7", args: args{tag: "[Group] -Name of a Novel Something Good- [2012][Translated (Group)][EPUB]", filter: "(?:.*Something Funny.*|.*Something Bad.*)"}, want: false},
{name: "test_8", args: args{tag: ".s10E123.", filter:`\.[Ss]\d{1,2}[Ee]\d{1,3}\.`}, want: true},
{name: "test_9", args: args{tag: "S1E1", filter:`\.[Ss]\d{1,2}[Ee]\d{1,3}\.`}, want: false},
{name: "test_8", args: args{tag: ".s10E123.", filter: `\.[Ss]\d{1,2}[Ee]\d{1,3}\.`}, want: true},
{name: "test_9", args: args{tag: "S1E1", filter: `\.[Ss]\d{1,2}[Ee]\d{1,3}\.`}, want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View file

@ -352,6 +352,8 @@ func (p *IndexerIRCParse) Parse(def *IndexerDefinition, vars map[string]string,
parser = IRCParserGazelleGames{}
case "ops":
parser = IRCParserOrpheus{}
case "redacted":
parser = IRCParserRedacted{}
default:
parser = IRCParserDefault{}
}

View file

@ -335,11 +335,14 @@ func TestIRCParserOrpheus_Parse(t *testing.T) {
rls: NewRelease("ops"),
vars: map[string]string{
"torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] WEB/FLAC/24bit Lossless",
"title": "Busta Rhymes BEACH BALL (feat. BIA)",
"year": "2023",
"releaseTags": "WEB/FLAC/24bit Lossless",
},
},
want: want{
title: "BEACH BALL",
release: "Busta Rhymes - BEACH BALL (feat. BIA) - [2023] [Single] WEB/FLAC/24bit Lossless",
title: "Busta Rhymes - BEACH BALL (feat. BIA)",
release: "Busta Rhymes - BEACH BALL (feat. BIA) [2023] (WEB FLAC 24BIT Lossless)",
},
},
{
@ -348,11 +351,14 @@ func TestIRCParserOrpheus_Parse(t *testing.T) {
rls: NewRelease("ops"),
vars: map[string]string{
"torrentName": "Busta Rhymes BEACH BALL (feat. BIA) [2023] [Single] CD/FLAC/Lossless",
"title": "Busta Rhymes BEACH BALL (feat. BIA)",
"year": "2023",
"releaseTags": "CD/FLAC/Lossless",
},
},
want: want{
title: "BEACH BALL",
release: "Busta Rhymes - BEACH BALL (feat. BIA) - [2023] [Single] CD/FLAC/Lossless",
title: "Busta Rhymes - BEACH BALL (feat. BIA)",
release: "Busta Rhymes - BEACH BALL (feat. BIA) [2023] (CD FLAC Lossless)",
},
},
}

View file

@ -6,6 +6,7 @@ package domain
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
)
@ -185,13 +186,88 @@ func (p IRCParserGazelleGames) Parse(rls *Release, vars map[string]string) error
type IRCParserOrpheus struct{}
func (p IRCParserOrpheus) replaceSeparator(s string) string {
return strings.ReplaceAll(s, "", "-")
}
func (p IRCParserOrpheus) Parse(rls *Release, vars map[string]string) error {
// OPS uses en-dashes as separators, which causes moistari/rls to not parse the torrentName properly,
// we replace the en-dashes with hyphens here
torrentName := vars["torrentName"]
rls.TorrentName = strings.ReplaceAll(torrentName, "", "-")
torrentName := p.replaceSeparator(vars["torrentName"])
title := p.replaceSeparator(vars["title"])
rls.ParseString(rls.TorrentName)
year := vars["year"]
releaseTagsString := vars["releaseTags"]
//cleanTags := strings.ReplaceAll(releaseTagsString, "/", " ")
cleanTags := CleanReleaseTags(releaseTagsString)
tags := ParseReleaseTagString(cleanTags)
rls.ReleaseTags = cleanTags
audio := []string{}
if tags.Source != "" {
audio = append(audio, tags.Source)
}
if tags.AudioFormat != "" {
audio = append(audio, tags.AudioFormat)
}
if tags.AudioBitrate != "" {
audio = append(audio, tags.AudioBitrate)
}
rls.Bitrate = tags.AudioBitrate
rls.AudioFormat = tags.AudioFormat
// set log score
rls.HasLog = tags.HasLog
rls.LogScore = tags.LogScore
rls.HasCue = tags.HasCue
// Construct new release name so we have full control. We remove category such as EP/Single/Album because EP is being mis-parsed.
//torrentName = fmt.Sprintf("%s [%s] (%s)", title, year, strings.Join(audio, " "))
torrentName = fmt.Sprintf("%s [%s] (%s)", title, year, strings.Join(audio, " "))
rls.ParseString(torrentName)
rls.Title = title
return nil
}
// IRCParserRedacted parser for Redacted announces
type IRCParserRedacted struct{}
func (p IRCParserRedacted) Parse(rls *Release, vars map[string]string) error {
title := vars["title"]
year := vars["year"]
releaseTagsString := vars["releaseTags"]
cleanTags := CleanReleaseTags(releaseTagsString)
tags := ParseReleaseTagString(cleanTags)
audio := []string{}
if tags.Source != "" {
audio = append(audio, tags.Source)
}
if tags.AudioFormat != "" {
audio = append(audio, tags.AudioFormat)
}
if tags.AudioBitrate != "" {
audio = append(audio, tags.AudioBitrate)
}
rls.Bitrate = tags.AudioBitrate
rls.AudioFormat = tags.AudioFormat
// set log score
rls.HasLog = tags.HasLog
rls.LogScore = tags.LogScore
rls.HasCue = tags.HasCue
// Construct new release name so we have full control. We remove category such as EP/Single/Album because EP is being mis-parsed.
name := fmt.Sprintf("%s [%s] (%s)", title, year, strings.Join(audio, " "))
rls.ParseString(name)
rls.Title = title
return nil
}

View file

@ -12,7 +12,6 @@ import (
"net/http"
"net/http/cookiejar"
"os"
"regexp"
"strconv"
"strings"
"time"
@ -75,6 +74,8 @@ type Release struct {
HDR []string `json:"hdr"`
Audio []string `json:"-"`
AudioChannels string `json:"-"`
AudioFormat string `json:"-"`
Bitrate string `json:"-"`
Group string `json:"group"`
Region string `json:"-"`
Language []string `json:"-"`
@ -84,6 +85,8 @@ type Release struct {
Artists string `json:"-"`
Type string `json:"type"` // Album,Single,EP
LogScore int `json:"-"`
HasCue bool `json:"-"`
HasLog bool `json:"-"`
Origin string `json:"origin"` // P2P, Internal
Tags []string `json:"-"`
ReleaseTags string `json:"-"`
@ -289,6 +292,8 @@ func NewRelease(indexer string) *Release {
func (r *Release) ParseString(title string) {
rel := rls.ParseString(title)
r.Type = rel.Type.String()
r.TorrentName = title
r.Source = rel.Source
r.Resolution = rel.Resolution
@ -327,18 +332,40 @@ func (r *Release) ParseString(title string) {
var ErrUnrecoverableError = errors.New("unrecoverable error")
func (r *Release) ParseReleaseTagsString(tags string) {
// trim delimiters and closest space
re := regexp.MustCompile(`\| |/ |, `)
cleanTags := re.ReplaceAllString(tags, "")
cleanTags := CleanReleaseTags(tags)
t := ParseReleaseTagString(cleanTags)
if len(t.Audio) > 0 {
r.Audio = getUniqueTags(r.Audio, t.Audio)
//r.Audio = getUniqueTags(r.Audio, t.Audio)
r.Audio = t.Audio
}
if t.AudioBitrate != "" {
r.Bitrate = t.AudioBitrate
}
if t.AudioFormat != "" {
r.AudioFormat = t.AudioFormat
}
if r.AudioChannels == "" && t.Channels != "" {
r.AudioChannels = t.Channels
}
if t.HasLog {
r.HasLog = true
if t.LogScore > 0 {
r.LogScore = t.LogScore
}
}
if t.HasCue {
r.HasCue = true
}
if len(t.Bonus) > 0 {
if sliceContainsSlice([]string{"Freeleech"}, t.Bonus) {
if sliceContainsSlice([]string{"Freeleech", "Freeleech!"}, t.Bonus) {
r.Freeleech = true
}
// TODO handle percent and other types
@ -363,9 +390,6 @@ func (r *Release) ParseReleaseTagsString(tags string) {
if r.Source == "" && t.Source != "" {
r.Source = t.Source
}
if r.AudioChannels == "" && t.Channels != "" {
r.AudioChannels = t.Channels
}
}
// ParseSizeBytesString If there are parsing errors, then it keeps the original (or default size 0)

View file

@ -0,0 +1,276 @@
// Copyright (c) 2021 - 2024, Ludvig Lundgren and the autobrr contributors.
// SPDX-License-Identifier: GPL-2.0-or-later
//go:build integration
package domain
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/rs/zerolog"
)
var trackerLessTestTorrent = `d7:comment19:This is just a test10:created by12:Johnny Bravo13:creation datei1430648794e8:encoding5:UTF-84:infod6:lengthi1128e4:name12:testfile.bin12:piece lengthi32768e6:pieces20:Õˆë =UŒäiÎ^æ °Eâ?ÇÒe5:nodesl35:udp://tracker.openbittorrent.com:8035:udp://tracker.openbittorrent.com:80ee`
func TestRelease_DownloadTorrentFile(t *testing.T) {
// disable logger
zerolog.SetGlobalLevel(zerolog.Disabled)
mux := http.NewServeMux()
ts := httptest.NewServer(mux)
defer ts.Close()
mux.HandleFunc("/files/valid_torrent_as_html", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html")
payload, _ := os.ReadFile("testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent")
w.Write(payload)
})
mux.HandleFunc("/files/invalid_torrent_as_html", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html")
payload := []byte("<html><head></head><body>This is not the torrent you are looking for</body></html>")
w.Write(payload)
})
mux.HandleFunc("/index.html", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html")
payload := []byte("<html><head></head><body>This is not the torrent you are looking for</body></html>")
w.Write(payload)
})
mux.HandleFunc("/plaintext", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/plain")
payload := []byte("This is not a valid torrent file.")
w.Write(payload)
})
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.RequestURI, "401") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("unauthorized"))
return
}
if strings.Contains(r.RequestURI, "403") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("forbidden"))
return
}
if strings.Contains(r.RequestURI, "404") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("not found"))
return
}
if strings.Contains(r.RequestURI, "405") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("method not allowed"))
return
}
if strings.Contains(r.RequestURI, "file.torrent") {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/x-bittorrent")
payload, _ := os.ReadFile("testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent")
w.Write(payload)
return
}
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal error"))
})
type fields struct {
ID int64
FilterStatus ReleaseFilterStatus
Rejections []string
Indexer string
FilterName string
Protocol ReleaseProtocol
Implementation ReleaseImplementation
Timestamp time.Time
GroupID string
TorrentID string
DownloadURL string
TorrentTmpFile string
TorrentDataRawBytes []byte
TorrentHash string
TorrentName string
Size uint64
Title string
Category string
Categories []string
Season int
Episode int
Year int
Resolution string
Source string
Codec []string
Container string
HDR []string
Audio []string
AudioChannels string
Group string
Region string
Language []string
Proper bool
Repack bool
Website string
Artists string
Type string
LogScore int
Origin string
Tags []string
ReleaseTags string
Freeleech bool
FreeleechPercent int
Bonus []string
Uploader string
PreTime string
Other []string
RawCookie string
AdditionalSizeCheckRequired bool
FilterID int
Filter *Filter
ActionStatus []ReleaseActionStatus
}
tests := []struct {
name string
fields fields
wantErr bool
}{
{
name: "401",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 401),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
{
name: "403",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 403),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
{
name: "500",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 500),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
{
name: "ok",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%s", ts.URL, "file.torrent"),
Protocol: ReleaseProtocolTorrent,
},
wantErr: false,
},
{
name: "valid_torrent_with_text-html_header",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/files/%s", ts.URL, "valid_torrent_as_html"),
Protocol: ReleaseProtocolTorrent,
},
wantErr: false,
},
{
name: "invalid_torrent_with_text-html_header",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/files/%s", ts.URL, "invalid_torrent_as_html"),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Release{
ID: tt.fields.ID,
FilterStatus: tt.fields.FilterStatus,
Rejections: tt.fields.Rejections,
Indexer: tt.fields.Indexer,
FilterName: tt.fields.FilterName,
Protocol: tt.fields.Protocol,
Implementation: tt.fields.Implementation,
Timestamp: tt.fields.Timestamp,
GroupID: tt.fields.GroupID,
TorrentID: tt.fields.TorrentID,
DownloadURL: tt.fields.DownloadURL,
TorrentTmpFile: tt.fields.TorrentTmpFile,
TorrentDataRawBytes: tt.fields.TorrentDataRawBytes,
TorrentHash: tt.fields.TorrentHash,
TorrentName: tt.fields.TorrentName,
Size: tt.fields.Size,
Title: tt.fields.Title,
Category: tt.fields.Category,
Categories: tt.fields.Categories,
Season: tt.fields.Season,
Episode: tt.fields.Episode,
Year: tt.fields.Year,
Resolution: tt.fields.Resolution,
Source: tt.fields.Source,
Codec: tt.fields.Codec,
Container: tt.fields.Container,
HDR: tt.fields.HDR,
Audio: tt.fields.Audio,
AudioChannels: tt.fields.AudioChannels,
Group: tt.fields.Group,
Region: tt.fields.Region,
Language: tt.fields.Language,
Proper: tt.fields.Proper,
Repack: tt.fields.Repack,
Website: tt.fields.Website,
Artists: tt.fields.Artists,
Type: tt.fields.Type,
LogScore: tt.fields.LogScore,
Origin: tt.fields.Origin,
Tags: tt.fields.Tags,
ReleaseTags: tt.fields.ReleaseTags,
Freeleech: tt.fields.Freeleech,
FreeleechPercent: tt.fields.FreeleechPercent,
Bonus: tt.fields.Bonus,
Uploader: tt.fields.Uploader,
PreTime: tt.fields.PreTime,
Other: tt.fields.Other,
RawCookie: tt.fields.RawCookie,
AdditionalSizeCheckRequired: tt.fields.AdditionalSizeCheckRequired,
FilterID: tt.fields.FilterID,
Filter: tt.fields.Filter,
ActionStatus: tt.fields.ActionStatus,
}
err := r.DownloadTorrentFile()
if err == nil && tt.wantErr {
fmt.Println("error")
}
})
}
}

View file

@ -4,15 +4,8 @@
package domain
import (
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
)
@ -40,6 +33,7 @@ func TestRelease_Parse(t *testing.T) {
HDR: []string{"DV"},
Group: "FLUX",
//Website: "ATVP",
Type: "series",
},
},
{
@ -59,6 +53,7 @@ func TestRelease_Parse(t *testing.T) {
AudioChannels: "5.1",
HDR: []string{"DV"},
Group: "FLUX",
Type: "series",
},
},
{
@ -81,6 +76,7 @@ func TestRelease_Parse(t *testing.T) {
AudioChannels: "5.1",
HDR: []string{"DV"},
Group: "FLUX",
Type: "series",
},
},
{
@ -103,6 +99,7 @@ func TestRelease_Parse(t *testing.T) {
AudioChannels: "5.1",
HDR: []string{"DV"},
Group: "FLUX",
Type: "series",
},
},
{
@ -125,6 +122,7 @@ func TestRelease_Parse(t *testing.T) {
AudioChannels: "5.1",
HDR: []string{"DV"},
Group: "FLUX",
Type: "series",
},
},
{
@ -149,6 +147,7 @@ func TestRelease_Parse(t *testing.T) {
Group: "FLUX",
Freeleech: true,
Bonus: []string{"Freeleech"},
Type: "series",
},
},
{
@ -163,7 +162,12 @@ func TestRelease_Parse(t *testing.T) {
Title: "Artist",
Group: "Albumname",
Audio: []string{"Cue", "FLAC", "Lossless", "Log100", "Log"},
AudioFormat: "FLAC",
Source: "CD",
Bitrate: "Lossless",
HasLog: true,
LogScore: 100,
HasCue: true,
},
},
{
@ -180,6 +184,8 @@ func TestRelease_Parse(t *testing.T) {
Title: "Various Artists - Music '21",
Source: "Cassette",
Audio: []string{"320", "MP3"},
AudioFormat: "MP3",
Bitrate: "320",
},
},
{
@ -194,7 +200,9 @@ func TestRelease_Parse(t *testing.T) {
Title: "The artist",
Group: "name",
Source: "CD",
Audio: []string{"MP3", "VBR"},
Audio: []string{"MP3", "VBR", "V0 (VBR)"},
AudioFormat: "MP3",
Bitrate: "V0 (VBR)",
},
},
{
@ -209,7 +217,12 @@ func TestRelease_Parse(t *testing.T) {
Title: "Artist",
Group: "Albumname",
Audio: []string{"Cue", "FLAC", "Lossless", "Log100", "Log"},
AudioFormat: "FLAC",
Source: "CD",
Bitrate: "Lossless",
HasLog: true,
LogScore: 100,
HasCue: true,
},
},
{
@ -224,7 +237,32 @@ func TestRelease_Parse(t *testing.T) {
Title: "Artist",
Group: "Albumname",
Audio: []string{"24BIT Lossless", "Cue", "FLAC", "Log100", "Log"},
AudioFormat: "FLAC",
Source: "CD",
Bitrate: "24BIT Lossless",
HasLog: true,
LogScore: 100,
HasCue: true,
},
},
{
name: "parse_music_6",
fields: Release{
TorrentName: "Artist - Albumname",
ReleaseTags: "FLAC / 24bit Lossless / Log / 78% / Cue / CD",
},
want: Release{
TorrentName: "Artist - Albumname",
ReleaseTags: "FLAC / 24bit Lossless / Log / 78% / Cue / CD",
Title: "Artist",
Group: "Albumname",
Audio: []string{"24BIT Lossless", "Cue", "FLAC", "Log78", "Log"},
AudioFormat: "FLAC",
Source: "CD",
Bitrate: "24BIT Lossless",
HasLog: true,
LogScore: 78,
HasCue: true,
},
},
{
@ -244,6 +282,7 @@ func TestRelease_Parse(t *testing.T) {
Year: 2007,
Group: "GROUP1",
Other: []string{"HYBRiD", "REMUX"},
Type: "movie",
},
},
{
@ -264,6 +303,7 @@ func TestRelease_Parse(t *testing.T) {
Group: "GROUP1",
Season: 1,
Language: []string{"ENGLiSH"},
Type: "series",
},
},
}
@ -663,264 +703,6 @@ func TestRelease_ParseString(t *testing.T) {
}
}
var trackerLessTestTorrent = `d7:comment19:This is just a test10:created by12:Johnny Bravo13:creation datei1430648794e8:encoding5:UTF-84:infod6:lengthi1128e4:name12:testfile.bin12:piece lengthi32768e6:pieces20:Õˆë =UŒäiÎ^æ °Eâ?ÇÒe5:nodesl35:udp://tracker.openbittorrent.com:8035:udp://tracker.openbittorrent.com:80ee`
func TestRelease_DownloadTorrentFile(t *testing.T) {
// disable logger
zerolog.SetGlobalLevel(zerolog.Disabled)
mux := http.NewServeMux()
ts := httptest.NewServer(mux)
defer ts.Close()
mux.HandleFunc("/files/valid_torrent_as_html", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html")
payload, _ := os.ReadFile("testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent")
w.Write(payload)
})
mux.HandleFunc("/files/invalid_torrent_as_html", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html")
payload := []byte("<html><head></head><body>This is not the torrent you are looking for</body></html>")
w.Write(payload)
})
mux.HandleFunc("/index.html", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/html")
payload := []byte("<html><head></head><body>This is not the torrent you are looking for</body></html>")
w.Write(payload)
})
mux.HandleFunc("/plaintext", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "text/plain")
payload := []byte("This is not a valid torrent file.")
w.Write(payload)
})
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.RequestURI, "401") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("unauthorized"))
return
}
if strings.Contains(r.RequestURI, "403") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("forbidden"))
return
}
if strings.Contains(r.RequestURI, "404") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("not found"))
return
}
if strings.Contains(r.RequestURI, "405") {
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("method not allowed"))
return
}
if strings.Contains(r.RequestURI, "file.torrent") {
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/x-bittorrent")
payload, _ := os.ReadFile("testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent")
w.Write(payload)
return
}
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal error"))
})
type fields struct {
ID int64
FilterStatus ReleaseFilterStatus
Rejections []string
Indexer string
FilterName string
Protocol ReleaseProtocol
Implementation ReleaseImplementation
Timestamp time.Time
GroupID string
TorrentID string
DownloadURL string
TorrentTmpFile string
TorrentDataRawBytes []byte
TorrentHash string
TorrentName string
Size uint64
Title string
Category string
Categories []string
Season int
Episode int
Year int
Resolution string
Source string
Codec []string
Container string
HDR []string
Audio []string
AudioChannels string
Group string
Region string
Language []string
Proper bool
Repack bool
Website string
Artists string
Type string
LogScore int
Origin string
Tags []string
ReleaseTags string
Freeleech bool
FreeleechPercent int
Bonus []string
Uploader string
PreTime string
Other []string
RawCookie string
AdditionalSizeCheckRequired bool
FilterID int
Filter *Filter
ActionStatus []ReleaseActionStatus
}
tests := []struct {
name string
fields fields
wantErr bool
}{
{
name: "401",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 401),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
{
name: "403",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 403),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
{
name: "500",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%d", ts.URL, 500),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
{
name: "ok",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/%s", ts.URL, "file.torrent"),
Protocol: ReleaseProtocolTorrent,
},
wantErr: false,
},
{
name: "valid_torrent_with_text-html_header",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/files/%s", ts.URL, "valid_torrent_as_html"),
Protocol: ReleaseProtocolTorrent,
},
wantErr: false,
},
{
name: "invalid_torrent_with_text-html_header",
fields: fields{
Indexer: "mock-indexer",
TorrentName: "Test.Release-GROUP",
DownloadURL: fmt.Sprintf("%s/files/%s", ts.URL, "invalid_torrent_as_html"),
Protocol: ReleaseProtocolTorrent,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Release{
ID: tt.fields.ID,
FilterStatus: tt.fields.FilterStatus,
Rejections: tt.fields.Rejections,
Indexer: tt.fields.Indexer,
FilterName: tt.fields.FilterName,
Protocol: tt.fields.Protocol,
Implementation: tt.fields.Implementation,
Timestamp: tt.fields.Timestamp,
GroupID: tt.fields.GroupID,
TorrentID: tt.fields.TorrentID,
DownloadURL: tt.fields.DownloadURL,
TorrentTmpFile: tt.fields.TorrentTmpFile,
TorrentDataRawBytes: tt.fields.TorrentDataRawBytes,
TorrentHash: tt.fields.TorrentHash,
TorrentName: tt.fields.TorrentName,
Size: tt.fields.Size,
Title: tt.fields.Title,
Category: tt.fields.Category,
Categories: tt.fields.Categories,
Season: tt.fields.Season,
Episode: tt.fields.Episode,
Year: tt.fields.Year,
Resolution: tt.fields.Resolution,
Source: tt.fields.Source,
Codec: tt.fields.Codec,
Container: tt.fields.Container,
HDR: tt.fields.HDR,
Audio: tt.fields.Audio,
AudioChannels: tt.fields.AudioChannels,
Group: tt.fields.Group,
Region: tt.fields.Region,
Language: tt.fields.Language,
Proper: tt.fields.Proper,
Repack: tt.fields.Repack,
Website: tt.fields.Website,
Artists: tt.fields.Artists,
Type: tt.fields.Type,
LogScore: tt.fields.LogScore,
Origin: tt.fields.Origin,
Tags: tt.fields.Tags,
ReleaseTags: tt.fields.ReleaseTags,
Freeleech: tt.fields.Freeleech,
FreeleechPercent: tt.fields.FreeleechPercent,
Bonus: tt.fields.Bonus,
Uploader: tt.fields.Uploader,
PreTime: tt.fields.PreTime,
Other: tt.fields.Other,
RawCookie: tt.fields.RawCookie,
AdditionalSizeCheckRequired: tt.fields.AdditionalSizeCheckRequired,
FilterID: tt.fields.FilterID,
Filter: tt.fields.Filter,
ActionStatus: tt.fields.ActionStatus,
}
err := r.DownloadTorrentFile()
if err == nil && tt.wantErr {
fmt.Println("error")
}
})
}
}
func Test_getUniqueTags(t *testing.T) {
type args struct {
target []string

View file

@ -6,6 +6,7 @@ package domain
import (
"fmt"
"regexp"
"strconv"
"github.com/autobrr/autobrr/pkg/errors"
)
@ -27,6 +28,8 @@ func init() {
{tag: "AAC", title: "Advanced Audio Coding (LC)", regexp: "", re: nil},
{tag: "AC3D", title: "", regexp: "ac[\\-\\._ ]?3d", re: nil},
{tag: "Atmos", title: "Dolby Atmos", regexp: "", re: nil},
{tag: "APS (VBR)", title: "APS Variable Bit Rate", regexp: "", re: nil},
{tag: "APX (VBR)", title: "APX Variable Bit Rate", regexp: "", re: nil},
{tag: "CBR", title: "Constant Bit Rate", regexp: "", re: nil},
{tag: "Cue", title: "Cue File", regexp: "", re: nil},
{tag: "DDPA", title: "Dolby Digital+ Atmos (E-AC-3+Atmos)", regexp: "dd[p\\+]a", re: nil},
@ -46,7 +49,7 @@ func init() {
{tag: "FLAC", title: "Free Lossless Audio Codec", regexp: "", re: nil},
{tag: "LiNE", title: "Line", regexp: "(?-i:L[iI]NE)", re: nil},
{tag: "Lossless", title: "", regexp: "(?i:(?:^|[^t] )Lossless)", re: nil},
{tag: "Log100", title: "", regexp: "(log 100%|log \\(100%\\))", re: nil},
{tag: "LogScore", title: "LogScore", regexp: "log\\s?(?:\\(|\\s)(\\d+)%\\)?", re: nil},
{tag: "Log", title: "", regexp: "(?:log)", re: nil},
{tag: "LPCM", title: "Linear Pulse-Code Modulation", regexp: "", re: nil},
{tag: "MP3", title: "", regexp: "", re: nil},
@ -54,9 +57,66 @@ func init() {
{tag: "OPUS", title: "", regexp: "", re: nil},
{tag: "TrueHD", title: "Dolby TrueHD", regexp: "(?:dolby[\\-\\._ ]?)?true[\\-\\._ ]?hd", re: nil},
{tag: "VBR", title: "Variable Bit Rate", regexp: "", re: nil},
{tag: "V0 (VBR)", title: "V0 Variable Bit Rate", regexp: "", re: nil},
{tag: "V1 (VBR)", title: "V1 Variable Bit Rate", regexp: "", re: nil},
{tag: "V2 (VBR)", title: "V2 Variable Bit Rate", regexp: "", re: nil},
}
types["audio"] = audio
audioBitrate := []*TagInfo{
{tag: "24BIT", title: "", regexp: "(?-i:24BIT)", re: nil},
{tag: "24BIT Lossless", title: "", regexp: "(?:24BIT lossless)", re: nil},
{tag: "16BIT", title: "", regexp: "(?-i:16BIT)", re: nil},
{tag: "320", title: "320 Kbps", regexp: "320[\\\\-\\\\._ kbps]?", re: nil},
{tag: "256", title: "256 Kbps", regexp: "256[\\\\-\\\\._ kbps]?", re: nil},
{tag: "192", title: "192 Kbps", regexp: "192[\\\\-\\\\._ kbps]?", re: nil},
{tag: "128", title: "128 Kbps", regexp: "128[\\\\-\\\\._ kbps]?", re: nil},
{tag: "APS (VBR)", title: "APS Variable Bit Rate", regexp: "", re: nil},
{tag: "APX (VBR)", title: "APX Variable Bit Rate", regexp: "", re: nil},
{tag: "CBR", title: "Constant Bit Rate", regexp: "", re: nil},
{tag: "Lossless", title: "", regexp: "(?i:(?:^|[^t] )Lossless)", re: nil},
{tag: "VBR", title: "Variable Bit Rate", regexp: "", re: nil},
{tag: "V0 (VBR)", title: "V0 Variable Bit Rate", regexp: "", re: nil},
{tag: "V1 (VBR)", title: "V1 Variable Bit Rate", regexp: "", re: nil},
{tag: "V2 (VBR)", title: "V2 Variable Bit Rate", regexp: "", re: nil},
}
types["audioBitrate"] = audioBitrate
audioFormat := []*TagInfo{
{tag: "AAC-LC", title: "Advanced Audio Coding (LC)", regexp: "aac[\\-\\._ ]?lc", re: nil},
{tag: "AAC", title: "Advanced Audio Coding (LC)", regexp: "", re: nil},
{tag: "AC3D", title: "", regexp: "ac[\\-\\._ ]?3d", re: nil},
{tag: "Atmos", title: "Dolby Atmos", regexp: "", re: nil},
{tag: "DDPA", title: "Dolby Digital+ Atmos (E-AC-3+Atmos)", regexp: "dd[p\\+]a", re: nil},
{tag: "DDP", title: "Dolby Digital+ (E-AC-3)", regexp: "dd[p\\+]|e[\\-\\._ ]?ac3", re: nil},
{tag: "DD", title: "Dolby Digital (AC-3)", regexp: "dd|ac3|dolby[\\-\\._ ]?digital", re: nil},
{tag: "DTS-HD.HRA", title: "DTS (HD HRA)", regexp: "dts[\\-\\._ ]?hd[\\-\\._ ]?hra", re: nil},
{tag: "DTS-HD.HR", title: "DTS (HD HR)", regexp: "dts[\\-\\._ ]?hd[\\-\\._ ]?hr", re: nil},
{tag: "DTS-HD.MA", title: "DTS (HD MA)", regexp: "dts[\\-\\._ ]?hd[\\-\\._ ]?ma", re: nil},
{tag: "DTS-HD", title: "DTS (HD)", regexp: "dts[\\-\\._ ]?hd[\\-\\._ ]?", re: nil},
{tag: "DTS-MA", title: "DTS (MA)", regexp: "dts[\\-\\._ ]?ma[\\-\\._ ]?", re: nil},
{tag: "DTS-X", title: "DTS (X)", regexp: "dts[\\-\\._ ]?x", re: nil},
{tag: "DTS", title: "", regexp: "", re: nil},
{tag: "EAC3D", title: "", regexp: "", re: nil},
{tag: "ES", title: "Dolby Digital (ES)", regexp: "(?-i:ES)", re: nil},
{tag: "EX", title: "Dolby Digital (EX)", regexp: "(?-i:EX)", re: nil},
{tag: "FLAC", title: "Free Lossless Audio Codec", regexp: "", re: nil},
{tag: "LPCM", title: "Linear Pulse-Code Modulation", regexp: "", re: nil},
{tag: "MP3", title: "", regexp: "", re: nil},
{tag: "OGG", title: "", regexp: "", re: nil},
{tag: "OPUS", title: "", regexp: "", re: nil},
{tag: "TrueHD", title: "Dolby TrueHD", regexp: "(?:dolby[\\-\\._ ]?)?true[\\-\\._ ]?hd", re: nil},
}
types["audioFormat"] = audioFormat
audioExtra := []*TagInfo{
{tag: "Cue", title: "Cue File", regexp: "", re: nil},
{tag: "Log100", title: "", regexp: "(log 100%|log \\(100%\\))", re: nil},
{tag: "LogScore", title: "LogScore", regexp: "log\\s?(?:\\(|\\s)(\\d+)%\\)?", re: nil},
{tag: "Log", title: "", regexp: "(?:log)", re: nil},
}
types["audioExtra"] = audioExtra
bonus := []*TagInfo{
{tag: "Freeleech", title: "Freeleech", regexp: "freeleech", re: nil},
}
@ -234,6 +294,11 @@ func (info *TagInfo) Regexp() string {
return info.regexp
}
// FindMatch returns the regexp matches.
func (info *TagInfo) FindMatch(t string) []string {
return info.re.FindStringSubmatch(t)
}
//// Other returns the tag info other.
//func (info *TagInfo) Other() string {
// return info.other
@ -279,16 +344,21 @@ func Find(infos ...*TagInfo) FindFunc {
}
type ReleaseTags struct {
Audio []string
Bonus []string
Channels string
Codec string
Container string
HDR []string
Origin string
Other []string
Resolution string
Source string
Audio []string
AudioBitrate string
AudioFormat string
LogScore int
HasLog bool
HasCue bool
Bonus []string
Channels string
Codec string
Container string
HDR []string
Origin string
Other []string
Resolution string
Source string
}
func ParseReleaseTags(tags []string) ReleaseTags {
@ -299,14 +369,32 @@ func ParseReleaseTags(tags []string) ReleaseTags {
for tagType, tagInfos := range types {
for _, info := range tagInfos {
if info.Tag() == "LogScore" {
m := info.FindMatch(tag)
if len(m) == 3 {
score, err := strconv.Atoi(m[2])
if err != nil {
// handle error
}
releaseTags.LogScore = score
}
continue
}
// check tag
match := info.Match(tag)
if match {
fmt.Printf("match: %v, info: %v\n", tag, info.Tag())
switch tagType {
case "audio":
releaseTags.Audio = append(releaseTags.Audio, info.Tag())
continue
case "audioBitrate":
releaseTags.AudioBitrate = info.Tag()
continue
case "audioFormat":
releaseTags.AudioFormat = info.Tag()
continue
case "bonus":
releaseTags.Bonus = append(releaseTags.Bonus, info.Tag())
continue
@ -347,7 +435,6 @@ func ParseReleaseTagString(tags string) ReleaseTags {
releaseTags := ReleaseTags{}
for tagType, tagInfos := range types {
//fmt.Printf("tagType: %v\n", tagType)
for _, info := range tagInfos {
// check tag
@ -356,10 +443,33 @@ func ParseReleaseTagString(tags string) ReleaseTags {
continue
}
//fmt.Printf("match: info: %v\n", info.Tag())
if info.Tag() == "LogScore" {
m := info.FindMatch(tags)
if len(m) == 2 {
score, err := strconv.Atoi(m[1])
if err != nil {
// handle error
}
releaseTags.HasLog = true
releaseTags.LogScore = score
releaseTags.Audio = append(releaseTags.Audio, fmt.Sprintf("Log%d", score))
}
continue
}
switch tagType {
case "audio":
releaseTags.Audio = append(releaseTags.Audio, info.Tag())
if info.Tag() == "Cue" {
releaseTags.HasCue = true
}
continue
case "audioBitrate":
releaseTags.AudioBitrate = info.Tag()
continue
case "audioFormat":
releaseTags.AudioFormat = info.Tag()
continue
case "bonus":
releaseTags.Bonus = append(releaseTags.Bonus, info.Tag())
@ -396,3 +506,10 @@ func ParseReleaseTagString(tags string) ReleaseTags {
return releaseTags
}
var tagsDelimiterRegexp = regexp.MustCompile(`\s*[|/,]\s*`)
// CleanReleaseTags trim delimiters and closest space
func CleanReleaseTags(tagString string) string {
return tagsDelimiterRegexp.ReplaceAllString(tagString, " ")
}

View file

@ -18,7 +18,7 @@ func TestParseReleaseTags(t *testing.T) {
args args
want ReleaseTags
}{
{name: "test_1", args: args{tags: []string{"CD", "FLAC", "Lossless"}}, want: ReleaseTags{Source: "CD", Audio: []string{"FLAC", "Lossless"}}},
{name: "test_1", args: args{tags: []string{"CD", "FLAC", "Lossless"}}, want: ReleaseTags{Audio: []string{"FLAC", "Lossless"}, AudioBitrate: "Lossless", AudioFormat: "FLAC", Source: "CD"}},
{name: "test_2", args: args{tags: []string{"MP4", "2160p", "BluRay", "DV"}}, want: ReleaseTags{Source: "BluRay", Resolution: "2160p", Container: "mp4", HDR: []string{"DV"}}},
}
for _, tt := range tests {
@ -37,12 +37,12 @@ func TestParseReleaseTagString(t *testing.T) {
args args
want ReleaseTags
}{
{name: "music_1", args: args{tags: "FLAC / Lossless / Log / 80% / Cue / CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log"}, Source: "CD"}},
{name: "music_2", args: args{tags: "FLAC Lossless Log 80% Cue CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log"}, Source: "CD"}},
{name: "music_3", args: args{tags: "FLAC Lossless Log 100% Cue CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log100", "Log"}, Source: "CD"}},
{name: "music_4", args: args{tags: "FLAC 24bit Lossless Log 100% Cue CD"}, want: ReleaseTags{Audio: []string{"24BIT Lossless", "Cue", "FLAC", "Log100", "Log"}, Source: "CD"}},
{name: "music_5", args: args{tags: "MP3 320 WEB"}, want: ReleaseTags{Audio: []string{"320", "MP3"}, Source: "WEB"}},
{name: "music_6", args: args{tags: "FLAC Lossless Log (100%) Cue CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log100", "Log"}, Source: "CD"}},
{name: "music_1", args: args{tags: "FLAC / Lossless / Log / 80% / Cue / CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log"}, AudioBitrate: "Lossless", AudioFormat: "FLAC", Source: "CD", HasCue: true}},
{name: "music_2", args: args{tags: "FLAC Lossless Log 80% Cue CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log80", "Log"}, AudioBitrate: "Lossless", AudioFormat: "FLAC", Source: "CD", HasLog: true, LogScore: 80, HasCue: true}},
{name: "music_3", args: args{tags: "FLAC Lossless Log 100% Cue CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log100", "Log"}, AudioBitrate: "Lossless", AudioFormat: "FLAC", Source: "CD", HasLog: true, LogScore: 100, HasCue: true}},
{name: "music_4", args: args{tags: "FLAC 24bit Lossless Log 100% Cue CD"}, want: ReleaseTags{Audio: []string{"24BIT Lossless", "Cue", "FLAC", "Log100", "Log"}, AudioBitrate: "24BIT Lossless", AudioFormat: "FLAC", Source: "CD", HasLog: true, LogScore: 100, HasCue: true}},
{name: "music_5", args: args{tags: "MP3 320 WEB"}, want: ReleaseTags{Audio: []string{"320", "MP3"}, AudioBitrate: "320", AudioFormat: "MP3", Source: "WEB"}},
{name: "music_6", args: args{tags: "FLAC Lossless Log (100%) Cue CD"}, want: ReleaseTags{Audio: []string{"Cue", "FLAC", "Lossless", "Log100", "Log"}, AudioBitrate: "Lossless", AudioFormat: "FLAC", Source: "CD", HasCue: true, HasLog: true, LogScore: 100}},
{name: "movies_1", args: args{tags: "x264 Blu-ray MKV 1080p"}, want: ReleaseTags{Codec: "x264", Source: "BluRay", Resolution: "1080p", Container: "mkv"}},
{name: "movies_2", args: args{tags: "HEVC HDR Blu-ray mp4 2160p"}, want: ReleaseTags{Codec: "HEVC", Source: "BluRay", Resolution: "2160p", Container: "mp4", HDR: []string{"HDR"}}},
{name: "movies_3", args: args{tags: "HEVC HDR DV Blu-ray mp4 2160p"}, want: ReleaseTags{Codec: "HEVC", Source: "BluRay", Resolution: "2160p", Container: "mp4", HDR: []string{"HDR", "DV"}}},
@ -51,9 +51,8 @@ func TestParseReleaseTagString(t *testing.T) {
{name: "movies_6", args: args{tags: "H.264, DVD"}, want: ReleaseTags{Codec: "H.264", Source: "DVD"}},
{name: "movies_7", args: args{tags: "H.264, DVD, Freeleech"}, want: ReleaseTags{Codec: "H.264", Source: "DVD", Bonus: []string{"Freeleech"}}},
{name: "movies_8", args: args{tags: "H.264, DVD, Freeleech!"}, want: ReleaseTags{Codec: "H.264", Source: "DVD", Bonus: []string{"Freeleech"}}},
{name: "anime_1", args: args{tags: "Web / MKV / h264 / 1080p / AAC 2.0 / Softsubs (SubsPlease) / Episode 22 / Freeleech"}, want: ReleaseTags{Audio: []string{"AAC"}, Channels: "2.0", Source: "WEB", Resolution: "1080p", Container: "mkv", Codec: "H.264", Bonus: []string{"Freeleech"}}},
{name: "anime_2", args: args{tags: "Web | ISO | h264 | 1080p | AAC 2.0 | Softsubs (SubsPlease) | Episode 22 | Freeleech"}, want: ReleaseTags{Audio: []string{"AAC"}, Channels: "2.0", Source: "WEB", Resolution: "1080p", Container: "iso", Codec: "H.264", Bonus: []string{"Freeleech"}}},
{name: "tv_1", args: args{tags: "MKV | H.264 | WEB-DL | 1080p | Internal | FastTorrent"}, want: ReleaseTags{Source: "WEB-DL", Codec: "H.264", Resolution: "1080p", Container: "mkv", Origin: "Internal"}},
{name: "anime_1", args: args{tags: "Web / MKV / h264 / 1080p / AAC 2.0 / Softsubs (SubsPlease) / Episode 22 / Freeleech"}, want: ReleaseTags{Audio: []string{"AAC"}, AudioBitrate: "", AudioFormat: "AAC", Bonus: []string{"Freeleech"}, Channels: "2.0", Codec: "H.264", Container: "mkv", Resolution: "1080p", Source: "WEB"}},
{name: "anime_2", args: args{tags: "Web | ISO | h264 | 1080p | AAC 2.0 | Softsubs (SubsPlease) | Episode 22 | Freeleech"}, want: ReleaseTags{Audio: []string{"AAC"}, AudioBitrate: "", AudioFormat: "AAC", Bonus: []string{"Freeleech"}, Channels: "2.0", Codec: "H.264", Container: "iso", Resolution: "1080p", Source: "WEB"}}, {name: "tv_1", args: args{tags: "MKV | H.264 | WEB-DL | 1080p | Internal | FastTorrent"}, want: ReleaseTags{Source: "WEB-DL", Codec: "H.264", Resolution: "1080p", Container: "mkv", Origin: "Internal"}},
{name: "tv_2", args: args{tags: "MKV | H.264 | WEB-DL | 1080p | Scene | FastTorrent"}, want: ReleaseTags{Source: "WEB-DL", Codec: "H.264", Resolution: "1080p", Container: "mkv", Origin: "Scene"}},
{name: "tv_3", args: args{tags: "MKV | H.264 | WEB-DL | 1080p | P2P | FastTorrent"}, want: ReleaseTags{Source: "WEB-DL", Codec: "H.264", Resolution: "1080p", Container: "mkv", Origin: "P2P"}},
}
@ -63,3 +62,23 @@ func TestParseReleaseTagString(t *testing.T) {
})
}
}
func Test_cleanReleaseTags(t *testing.T) {
type args struct {
tagString string
}
tests := []struct {
name string
args args
want string
}{
{name: "1", args: args{tagString: "FLAC / Lossless / Log / 100% / Cue / CD"}, want: "FLAC Lossless Log 100% Cue CD"},
{name: "2", args: args{tagString: "FLAC/Lossless/Log 100%/Cue/CD"}, want: "FLAC Lossless Log 100% Cue CD"},
{name: "3", args: args{tagString: "FLAC | Lossless | Log | 100% | Cue | CD"}, want: "FLAC Lossless Log 100% Cue CD"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, CleanReleaseTags(tt.args.tagString), "cleanReleaseTags(%v)", tt.args.tagString)
})
}
}