Skip to content

Commit

Permalink
andd better batch handling
Browse files Browse the repository at this point in the history
  • Loading branch information
sonalys committed Feb 8, 2024
1 parent 0a99d36 commit 69dba75
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 26 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ go 1.21.6

require (
github.com/rs/zerolog v1.32.0
github.com/stretchr/testify v1.8.4
golang.org/x/time v0.5.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.12.0 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
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/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
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 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
Expand Down
62 changes: 40 additions & 22 deletions internal/discovery/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ import (
"github.com/sonalys/animeman/internal/parser"
)

type TaggedNyaa struct {
meta parser.ParsedTitle
seasonEpisodeTag string
entry nyaa.Entry
}

func (c *Controller) RunDiscovery(ctx context.Context) error {
t1 := time.Now()
entries, err := c.dep.MAL.GetAnimeList(ctx,
Expand Down Expand Up @@ -41,15 +47,18 @@ func (c *Controller) RunDiscovery(ctx context.Context) error {
return nil
}

type TaggedNyaa struct {
meta parser.ParsedTitle
seasonEpisodeTag string
entry nyaa.Entry
func filterNyaaBatch(entries []nyaa.Entry) []nyaa.Entry {
for _, entry := range entries {
if meta := parser.ParseTitle(entry.Title); meta.IsMultiEpisode {
return []nyaa.Entry{entry}
}
}
return entries
}

func buildTaggedNyaaList(torrents []nyaa.Entry) []TaggedNyaa {
out := make([]TaggedNyaa, 0, len(torrents))
for _, entry := range torrents {
func buildTaggedNyaaList(entries []nyaa.Entry) []TaggedNyaa {
out := make([]TaggedNyaa, 0, len(entries))
for _, entry := range entries {
meta := parser.ParseTitle(entry.Title)
out = append(out, TaggedNyaa{
meta: meta,
Expand All @@ -63,43 +72,52 @@ func buildTaggedNyaaList(torrents []nyaa.Entry) []TaggedNyaa {
return out
}

func filterEpisodes(list []TaggedNyaa, latestTag string) []TaggedNyaa {
out := make([]TaggedNyaa, 0, len(list))
for _, nyaaEntry := range list {
// Make sure we only add episodes ahead of the current ones in the qBittorrent.
if compareTags(nyaaEntry.seasonEpisodeTag, latestTag) <= 0 {
continue
}
latestTag = nyaaEntry.seasonEpisodeTag
out = append(out, nyaaEntry)
}
return out
}

func (c *Controller) DigestMALEntry(ctx context.Context, entry myanimelist.AnimeListEntry) (count int, err error) {
// Build search query for Nyaa.
// For title we filter for english and original titles.
titleQuery := nyaa.OrQuery{parser.StripTitle(entry.TitleEng), parser.StripTitle(entry.Title)}
sourceQuery := nyaa.OrQuery(c.dep.Config.Sources)
qualityQuery := nyaa.OrQuery(c.dep.Config.Qualitites)

torrents, err := c.dep.NYAA.List(ctx, titleQuery, sourceQuery, qualityQuery)
log.Debug().Str("entry", entry.GetTitle()).Msgf("found %d torrents", len(torrents))
nyaaEntries, err := c.dep.NYAA.List(ctx, titleQuery, sourceQuery, qualityQuery)
log.Debug().Str("entry", entry.GetTitle()).Msgf("found %d torrents", len(nyaaEntries))
if err != nil {
return 0, fmt.Errorf("getting nyaa list: %w", err)
}
// There should always be torrents for entries, if there aren't we can just exit the routine.
if len(torrents) == 0 {
if len(nyaaEntries) == 0 {
log.Error().Msgf("no torrents found for entry '%s'", entry.GetTitle())
return 0, nil
}
latestTag, err := c.GetLatestTag(ctx, entry)
if err != nil {
return count, fmt.Errorf("getting latest tag: %w", err)
}
taggedNyaaList := buildTaggedNyaaList(torrents)
// If we don't have any episodes, and show is released, try to find a batch for all episodes.
if latestTag == "" && entry.AiringStatus == myanimelist.AiringStatusAired {
nyaaEntries = filterNyaaBatch(nyaaEntries)
}
taggedNyaaList := buildTaggedNyaaList(nyaaEntries)
taggedNyaaList = filterEpisodes(taggedNyaaList, latestTag)
for _, nyaaEntry := range taggedNyaaList {
// Make sure we only add episodes ahead of the current ones in the qBittorrent.
if compareTags(nyaaEntry.seasonEpisodeTag, latestTag) <= 0 {
continue
}
latestTag = nyaaEntry.seasonEpisodeTag
log.Debug().Str("entry", entry.GetTitle()).Msgf("analyzing torrent '%s'", nyaaEntry.meta.Title)
added, err := c.DigestNyaaTorrent(ctx, entry, nyaaEntry)
if err != nil {
if err := c.DigestNyaaTorrent(ctx, entry, nyaaEntry); err != nil {
log.Error().Msgf("failed to digest nyaa entry: %s", err)
continue
}
if added {
count++
}
count++
}
return count, nil
}
93 changes: 93 additions & 0 deletions internal/discovery/discovery_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package discovery

import (
"reflect"
"testing"

"github.com/sonalys/animeman/integrations/nyaa"
"github.com/stretchr/testify/require"
)

func Test_filterEpisodes(t *testing.T) {
type args struct {
list []TaggedNyaa
latestTag string
}
tests := []struct {
name string
args args
want []TaggedNyaa
}{
{
name: "empty",
args: args{},
want: []TaggedNyaa{},
},
{
name: "no tag",
args: args{
latestTag: "",
list: []TaggedNyaa{
{seasonEpisodeTag: "!Show3 S03E01"},
{seasonEpisodeTag: "!Show3 S03E02"},
},
},
want: []TaggedNyaa{
{seasonEpisodeTag: "!Show3 S03E01"},
{seasonEpisodeTag: "!Show3 S03E02"},
},
},
{
name: "tag",
args: args{
latestTag: "!Show3 S03E01",
list: []TaggedNyaa{
{seasonEpisodeTag: "!Show3 S03E01"},
{seasonEpisodeTag: "!Show3 S03E02"},
},
},
want: []TaggedNyaa{
{seasonEpisodeTag: "!Show3 S03E02"},
},
},
{
name: "season batch",
args: args{
latestTag: "!Show3 S03",
list: []TaggedNyaa{
{seasonEpisodeTag: "!Show3 S03E01"},
{seasonEpisodeTag: "!Show3 S03E02"},
},
},
want: []TaggedNyaa{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := filterEpisodes(tt.args.list, tt.args.latestTag); !reflect.DeepEqual(got, tt.want) {
t.Errorf("filterEpisodes() = %v, want %v", got, tt.want)
}
})
}
}

func Test_buildTaggedNyaaList(t *testing.T) {
t.Run("empty", func(t *testing.T) {
got := buildTaggedNyaaList([]nyaa.Entry{})
require.Empty(t, got)
})
t.Run("sort by tag", func(t *testing.T) {
input := []nyaa.Entry{
{Title: "Show3: S03E03"},
{Title: "Show3: S03E02"},
{Title: "Show3: S03E01"},
{Title: "Show3: S03"},
}
got := buildTaggedNyaaList(input)
require.Len(t, got, len(input))
latestTag := got[len(got)-1].seasonEpisodeTag
for i := range got {
require.True(t, compareTags(got[i].seasonEpisodeTag, latestTag) <= 0)
}
})
}
8 changes: 4 additions & 4 deletions internal/discovery/torrent.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ func (c *Controller) GetLatestTag(ctx context.Context, entry myanimelist.AnimeLi
return getLatestTag(append(torrents1, torrents2...)...), nil
}

func (c *Controller) DigestNyaaTorrent(ctx context.Context, entry myanimelist.AnimeListEntry, nyaaEntry TaggedNyaa) (bool, error) {
func (c *Controller) DigestNyaaTorrent(ctx context.Context, entry myanimelist.AnimeListEntry, nyaaEntry TaggedNyaa) error {
if nyaaEntry.meta.IsMultiEpisode && entry.AiringStatus == myanimelist.AiringStatusAiring {
log.Debug().Msgf("torrent dropped: multi-episode for currently airing")
return false, nil
return nil
}
var savePath qbittorrent.SavePath
if c.dep.Config.CreateShowFolder {
Expand All @@ -105,11 +105,11 @@ func (c *Controller) DigestNyaaTorrent(ctx context.Context, entry myanimelist.An
qbittorrent.Category(c.dep.Config.Category),
)
if err != nil {
return false, fmt.Errorf("adding torrents: %w", err)
return fmt.Errorf("adding torrents: %w", err)
}
log.Info().
Str("savePath", string(savePath)).
Strs("tag", tags).
Msgf("torrent added")
return true, nil
return nil
}

0 comments on commit 69dba75

Please sign in to comment.