Refactor return type of the search
This commit is contained in:
+14
-10
@@ -4,11 +4,14 @@ import (
|
||||
"encoding/xml"
|
||||
|
||||
pb "homelab.lan/music-agregator/gen/music_agregator/indexer/v1"
|
||||
"homelab.lan/music-agregator/internal/tracker/rutracker"
|
||||
)
|
||||
|
||||
var parserFactory = rutracker.NewParserFactory()
|
||||
|
||||
type SearchResult struct {
|
||||
XMLName xml.Name `xml:"rss"`
|
||||
Items []Item `xml:"channel>item"` // Directly targets items inside channel
|
||||
Items []Item `xml:"channel>item"`
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
@@ -38,7 +41,6 @@ func (sr *SearchResult) ToProto() *pb.SearchResponse {
|
||||
pbItems := make([]*pb.SearchItem, len(sr.Items))
|
||||
|
||||
for i, item := range sr.Items {
|
||||
// Map Torznab Attributes
|
||||
pbAttrs := make([]*pb.TorznabAttr, len(item.TorznabAttrs))
|
||||
for j, attr := range item.TorznabAttrs {
|
||||
pbAttrs[j] = &pb.TorznabAttr{
|
||||
@@ -47,21 +49,23 @@ func (sr *SearchResult) ToProto() *pb.SearchResponse {
|
||||
}
|
||||
}
|
||||
|
||||
// Map the Item
|
||||
release := parserFactory.GetParser(item.Categories).Parse(item.Title)
|
||||
|
||||
pbItems[i] = &pb.SearchItem{
|
||||
Title: item.Title,
|
||||
Link: item.Link,
|
||||
Guid: item.Guid,
|
||||
PubDate: item.PubDate,
|
||||
Size: item.Size,
|
||||
Description: item.Description,
|
||||
Categories: item.Categories,
|
||||
Title: item.Title,
|
||||
DownloadLink: item.Link,
|
||||
TorrentPageUrl: item.Guid,
|
||||
PubDate: item.PubDate,
|
||||
Size: item.Size,
|
||||
Description: item.Description,
|
||||
Categories: item.Categories,
|
||||
Enclosure: &pb.Enclosure{
|
||||
Url: item.Enclosure.URL,
|
||||
Length: item.Enclosure.Length,
|
||||
Type: item.Enclosure.Type,
|
||||
},
|
||||
TorznabAttrs: pbAttrs,
|
||||
Release: release.ToProto(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package indexer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"google.golang.org/grpc"
|
||||
@@ -12,39 +11,28 @@ import (
|
||||
)
|
||||
|
||||
type IndexerServer struct {
|
||||
indexer Indexer
|
||||
|
||||
service *IndexerService
|
||||
pb.UnimplementedIndexerServiceServer
|
||||
}
|
||||
|
||||
func NewIndexerServer(cfg config.Config) (*IndexerServer, error) {
|
||||
switch cfg.Indexer.Type {
|
||||
case config.IndexerTypeJackett:
|
||||
indexer := NewIndexer(cfg)
|
||||
return &IndexerServer{indexer: indexer}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unable to create the indexer for type: %v", cfg.Indexer.Type)
|
||||
service, err := NewIndexerService(cfg)
|
||||
if err != nil {
|
||||
log.Err(err).Msg("Failed to initialize IndexerService")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &IndexerServer{service: service}, nil
|
||||
}
|
||||
|
||||
func (server *IndexerServer) Search(ctx context.Context, req *pb.SearchRequest) (*pb.SearchResponse, error) {
|
||||
log.Debug().Str("query", req.GetQuery()).Int32("limit", req.GetLimit()).Str("indexer", req.GetTracker()).Msg("Running search with these prams")
|
||||
searchResult, err := server.indexer.Search(req.GetQuery(), req.GetLimit(), req.GetTracker())
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to search in indexer")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return searchResult.ToProto(), nil
|
||||
return server.service.Search(req)
|
||||
}
|
||||
|
||||
func (server *IndexerServer) Capabilities(ctx context.Context, req *pb.CapabilitiesRequest) (*pb.CapabilitiesResponse, error) {
|
||||
capabilities, err := server.indexer.Capabilities(req.GetIndexer())
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get capabilities from indexer")
|
||||
return nil, err
|
||||
}
|
||||
return capabilities.ToProto(), nil
|
||||
return server.service.Capabilities(req)
|
||||
}
|
||||
|
||||
func (s *IndexerServer) Register(server *grpc.Server) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package indexer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
pb "homelab.lan/music-agregator/gen/music_agregator/indexer/v1"
|
||||
"homelab.lan/music-agregator/internal/config"
|
||||
)
|
||||
|
||||
type IndexerService struct {
|
||||
indexer Indexer
|
||||
}
|
||||
|
||||
func NewIndexerService(cfg config.Config) (*IndexerService, error) {
|
||||
switch cfg.Indexer.Type {
|
||||
case config.IndexerTypeJackett:
|
||||
indexer := NewIndexer(cfg)
|
||||
return &IndexerService{indexer: indexer}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unable to create the indexer for type: %v", cfg.Indexer.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (service *IndexerService) Search(req *pb.SearchRequest) (*pb.SearchResponse, error) {
|
||||
searchResult, err := service.indexer.Search(req.GetQuery(), req.GetLimit(), req.GetTracker())
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to search in indexer")
|
||||
return nil, err
|
||||
}
|
||||
return searchResult.ToProto(), nil
|
||||
}
|
||||
|
||||
func (service *IndexerService) Capabilities(req *pb.CapabilitiesRequest) (*pb.CapabilitiesResponse, error) {
|
||||
capabilities, err := service.indexer.Capabilities(req.GetIndexer())
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get capabilities from indexer")
|
||||
return nil, err
|
||||
}
|
||||
return capabilities.ToProto(), nil
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
package release
|
||||
|
||||
import (
|
||||
pb "homelab.lan/music-agregator/gen/music_agregator/indexer/v1"
|
||||
)
|
||||
|
||||
type Type int
|
||||
|
||||
const (
|
||||
@@ -176,3 +180,30 @@ func (r *Release) IsSingleRelease() bool {
|
||||
func (r *Release) HasYearRange() bool {
|
||||
return r.YearEnd > 0 && r.YearEnd != r.Year
|
||||
}
|
||||
|
||||
func (r *Release) ToProto() *pb.Release {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return &pb.Release{
|
||||
RawTitle: r.RawTitle,
|
||||
Artist: r.Artist,
|
||||
Album: r.Album,
|
||||
Year: int32(r.Year),
|
||||
YearEnd: int32(r.YearEnd),
|
||||
Type: r.Type.String(),
|
||||
Genres: r.Genres,
|
||||
Format: r.Format.String(),
|
||||
Source: r.Source.String(),
|
||||
Bitrate: r.Bitrate,
|
||||
BitDepth: int32(r.BitDepth),
|
||||
SampleRate: int32(r.SampleRate),
|
||||
RipType: r.RipType,
|
||||
ReleaseCount: int32(r.ReleaseCount),
|
||||
Tags: r.Tags,
|
||||
Label: r.Label,
|
||||
CatalogNum: r.CatalogNum,
|
||||
ParsedSuccessfully: r.ParsedSuccessfully,
|
||||
ParseErrors: r.ParseErrors,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package tracker
|
||||
|
||||
type ParserFactory interface {
|
||||
GetParser(categories []string) Parser
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package parser
|
||||
package tracker
|
||||
|
||||
import "homelab.lan/music-agregator/internal/release"
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package rutracker
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"homelab.lan/music-agregator/internal/tracker"
|
||||
"homelab.lan/music-agregator/internal/tracker/rutracker/parser"
|
||||
)
|
||||
|
||||
type parserType int
|
||||
|
||||
const (
|
||||
parserGeneral parserType = iota
|
||||
parserLossless
|
||||
parserLossy
|
||||
parserHiRes
|
||||
parserVinylDigitization
|
||||
parserClassical
|
||||
parserJazz
|
||||
parserMetal
|
||||
parserSoundtracks
|
||||
parserDiscography
|
||||
parserLabelPacks
|
||||
)
|
||||
|
||||
var categoryToParser map[int]parserType
|
||||
|
||||
func init() {
|
||||
categoryToParser = make(map[int]parserType)
|
||||
|
||||
torznabCategories := map[int]parserType{
|
||||
3000: parserGeneral,
|
||||
3010: parserLossy,
|
||||
3040: parserLossless,
|
||||
}
|
||||
|
||||
losslessForumIDs := []int{
|
||||
425, 429, 1760, 1635, 1634, 2495, 1299, 1141, 1660, 1662, 1661, 1852, 1648,
|
||||
1851, 1850, 1633, 1632, 1643, 1846, 2219, 2220, 2221, 1647, 1847, 1848, 1653,
|
||||
738, 739, 740, 1656, 1654, 1655, 1843, 1841, 1842, 408, 1844, 1845, 1849,
|
||||
1650, 1651, 1652, 1659, 1657, 1658, 445, 1664, 1665, 1666, 1669, 1667, 1668,
|
||||
1906, 1907, 1908, 1911, 1909, 1910,
|
||||
}
|
||||
|
||||
lossyForumIDs := []int{
|
||||
424, 428, 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 441, 446,
|
||||
1765, 1766, 1767, 1768, 1769, 1770, 1771,
|
||||
}
|
||||
|
||||
hiResForumIDs := []int{
|
||||
1801, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817,
|
||||
2378, 2379, 2380, 2381, 2382, 2383, 2384,
|
||||
}
|
||||
|
||||
vinylForumIDs := []int{
|
||||
1802, 1803, 1804, 1805, 1806,
|
||||
}
|
||||
|
||||
classicalForumIDs := []int{
|
||||
436, 969, 1990, 984, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132,
|
||||
1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677,
|
||||
}
|
||||
|
||||
jazzForumIDs := []int{
|
||||
1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709,
|
||||
}
|
||||
|
||||
metalForumIDs := []int{
|
||||
731, 732, 733, 734, 735, 736, 737, 738, 739, 740,
|
||||
1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 1738, 1739,
|
||||
}
|
||||
|
||||
soundtrackForumIDs := []int{
|
||||
691, 702, 704, 705, 706, 707, 708, 709, 710, 711,
|
||||
1631, 469, 786,
|
||||
}
|
||||
|
||||
for id, pt := range torznabCategories {
|
||||
categoryToParser[id] = pt
|
||||
}
|
||||
for _, id := range losslessForumIDs {
|
||||
categoryToParser[id] = parserLossless
|
||||
}
|
||||
for _, id := range lossyForumIDs {
|
||||
categoryToParser[id] = parserLossy
|
||||
}
|
||||
for _, id := range hiResForumIDs {
|
||||
categoryToParser[id] = parserHiRes
|
||||
}
|
||||
for _, id := range vinylForumIDs {
|
||||
categoryToParser[id] = parserVinylDigitization
|
||||
}
|
||||
for _, id := range classicalForumIDs {
|
||||
categoryToParser[id] = parserClassical
|
||||
}
|
||||
for _, id := range jazzForumIDs {
|
||||
categoryToParser[id] = parserJazz
|
||||
}
|
||||
for _, id := range metalForumIDs {
|
||||
categoryToParser[id] = parserMetal
|
||||
}
|
||||
for _, id := range soundtrackForumIDs {
|
||||
categoryToParser[id] = parserSoundtracks
|
||||
}
|
||||
}
|
||||
|
||||
type ParserFactory struct {
|
||||
parsers map[parserType]tracker.Parser
|
||||
}
|
||||
|
||||
func NewParserFactory() *ParserFactory {
|
||||
return &ParserFactory{
|
||||
parsers: map[parserType]tracker.Parser{
|
||||
parserGeneral: parser.NewGeneralParser(),
|
||||
parserLossless: parser.NewLosslessParser(),
|
||||
parserLossy: parser.NewLossyParser(),
|
||||
parserHiRes: parser.NewHiResParser(),
|
||||
parserVinylDigitization: parser.NewVinylDigitizationParser(),
|
||||
parserClassical: parser.NewClassicalParser(),
|
||||
parserJazz: parser.NewJazzParser(),
|
||||
parserMetal: parser.NewMetalParser(),
|
||||
parserSoundtracks: parser.NewSoundtracksParser(),
|
||||
parserDiscography: parser.NewDiscographyParser(),
|
||||
parserLabelPacks: parser.NewLabelPacksParser(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (f *ParserFactory) GetParser(categories []string) tracker.Parser {
|
||||
for _, cat := range categories {
|
||||
catID, err := strconv.Atoi(cat)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if pt, ok := categoryToParser[catID]; ok {
|
||||
return f.parsers[pt]
|
||||
}
|
||||
}
|
||||
return f.parsers[parserGeneral]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package rutracker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"homelab.lan/music-agregator/internal/tracker"
|
||||
"homelab.lan/music-agregator/internal/tracker/rutracker/parser"
|
||||
)
|
||||
|
||||
func TestParserFactory_GetParser(t *testing.T) {
|
||||
f := NewParserFactory()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
categories []string
|
||||
wantType string
|
||||
}{
|
||||
{"torznab lossless", []string{"3040"}, "*parser.LosslessParser"},
|
||||
{"torznab lossy", []string{"3010"}, "*parser.LossyParser"},
|
||||
{"torznab general", []string{"3000"}, "*parser.GeneralParser"},
|
||||
{"rutracker lossless forum", []string{"425"}, "*parser.LosslessParser"},
|
||||
{"rutracker lossy forum", []string{"424"}, "*parser.LossyParser"},
|
||||
{"rutracker hires forum", []string{"1801"}, "*parser.HiResParser"},
|
||||
{"rutracker vinyl forum", []string{"1802"}, "*parser.VinylDigitizationParser"},
|
||||
{"rutracker classical forum", []string{"436"}, "*parser.ClassicalParser"},
|
||||
{"rutracker jazz forum", []string{"1698"}, "*parser.JazzParser"},
|
||||
{"rutracker metal forum", []string{"731"}, "*parser.MetalParser"},
|
||||
{"rutracker soundtrack forum", []string{"691"}, "*parser.SoundtracksParser"},
|
||||
{"unknown category falls back to general", []string{"99999"}, "*parser.GeneralParser"},
|
||||
{"empty categories falls back to general", []string{}, "*parser.GeneralParser"},
|
||||
{"multiple categories uses first match", []string{"99999", "3040"}, "*parser.LosslessParser"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
p := f.GetParser(tt.categories)
|
||||
gotType := getParserTypeName(p)
|
||||
if gotType != tt.wantType {
|
||||
t.Errorf("GetParser(%v) = %v, want %v", tt.categories, gotType, tt.wantType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getParserTypeName(p tracker.Parser) string {
|
||||
switch p.(type) {
|
||||
case *parser.GeneralParser:
|
||||
return "*parser.GeneralParser"
|
||||
case *parser.LosslessParser:
|
||||
return "*parser.LosslessParser"
|
||||
case *parser.LossyParser:
|
||||
return "*parser.LossyParser"
|
||||
case *parser.HiResParser:
|
||||
return "*parser.HiResParser"
|
||||
case *parser.VinylDigitizationParser:
|
||||
return "*parser.VinylDigitizationParser"
|
||||
case *parser.ClassicalParser:
|
||||
return "*parser.ClassicalParser"
|
||||
case *parser.JazzParser:
|
||||
return "*parser.JazzParser"
|
||||
case *parser.MetalParser:
|
||||
return "*parser.MetalParser"
|
||||
case *parser.SoundtracksParser:
|
||||
return "*parser.SoundtracksParser"
|
||||
case *parser.DiscographyParser:
|
||||
return "*parser.DiscographyParser"
|
||||
case *parser.LabelPacksParser:
|
||||
return "*parser.LabelPacksParser"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
@@ -36,5 +36,3 @@ func (p *ClassicalParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*ClassicalParser)(nil)
|
||||
|
||||
@@ -52,5 +52,3 @@ func (p *DiscographyParser) extractDiscographyArtist(title string) string {
|
||||
artist, _ := p.ExtractArtistAlbum(title)
|
||||
return artist
|
||||
}
|
||||
|
||||
var _ Parser = (*DiscographyParser)(nil)
|
||||
|
||||
@@ -33,5 +33,3 @@ func (p *GeneralParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*GeneralParser)(nil)
|
||||
|
||||
@@ -43,5 +43,3 @@ func (p *HiResParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*HiResParser)(nil)
|
||||
|
||||
@@ -36,5 +36,3 @@ func (p *JazzParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*JazzParser)(nil)
|
||||
|
||||
@@ -31,5 +31,3 @@ func (p *LabelPacksParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*LabelPacksParser)(nil)
|
||||
|
||||
@@ -35,5 +35,3 @@ func (p *LosslessParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*LosslessParser)(nil)
|
||||
|
||||
@@ -34,5 +34,3 @@ func (p *LossyParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*LossyParser)(nil)
|
||||
|
||||
@@ -36,5 +36,3 @@ func (p *MetalParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*MetalParser)(nil)
|
||||
|
||||
@@ -32,5 +32,3 @@ func (p *SoundtracksParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*SoundtracksParser)(nil)
|
||||
|
||||
@@ -40,5 +40,3 @@ func (p *VinylDigitizationParser) Parse(title string) *release.Release {
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
var _ Parser = (*VinylDigitizationParser)(nil)
|
||||
|
||||
Reference in New Issue
Block a user