From b448e076bc3d278c48b8386ea3e470c084fea760 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 1 Jul 2026 20:07:31 +0200 Subject: [PATCH] Leftovers --- cmd/music-agregator/main.go | 2 +- gen/music_agregator/v1/music_agregator.pb.go | 605 +++++++++++------- .../v1/music_agregator_grpc.pb.go | 38 ++ internal/database/download_repository.go | 13 + internal/monitor_workflow.go | 14 +- internal/server.go | 9 +- internal/service.go | 378 +++++++++-- internal/tracker/magnet.go | 14 + .../music_agregator/v1/music_agregator.proto | 11 + 9 files changed, 793 insertions(+), 291 deletions(-) diff --git a/cmd/music-agregator/main.go b/cmd/music-agregator/main.go index 5458c2f..a64dde3 100644 --- a/cmd/music-agregator/main.go +++ b/cmd/music-agregator/main.go @@ -201,7 +201,7 @@ func serveGrpc(config config.Config) { rs := setupRiver(ctx, config, db, torrentClient, pathMapper, musicfsClient, metadataService, bus) - musiscAgregatorSeerver, err := internal.NewMusicAgregatorServer(config, rs.client, torrentClient, pathMapper, db, bus) + musiscAgregatorSeerver, err := internal.NewMusicAgregatorServer(config, rs.client, torrentClient, pathMapper, db, bus, musicfsClient) if err != nil { log.Fatal().Err(err).Msg("failed to create MusicAgregatorServer") } diff --git a/gen/music_agregator/v1/music_agregator.pb.go b/gen/music_agregator/v1/music_agregator.pb.go index 7d07539..1cbb9b8 100644 --- a/gen/music_agregator/v1/music_agregator.pb.go +++ b/gen/music_agregator/v1/music_agregator.pb.go @@ -290,6 +290,110 @@ func (PromptType) EnumDescriptor() ([]byte, []int) { return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{4} } +type ResyncAlbumRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + AlbumId string `protobuf:"bytes,1,opt,name=album_id,json=albumId,proto3" json:"album_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResyncAlbumRequest) Reset() { + *x = ResyncAlbumRequest{} + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResyncAlbumRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResyncAlbumRequest) ProtoMessage() {} + +func (x *ResyncAlbumRequest) ProtoReflect() protoreflect.Message { + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResyncAlbumRequest.ProtoReflect.Descriptor instead. +func (*ResyncAlbumRequest) Descriptor() ([]byte, []int) { + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{0} +} + +func (x *ResyncAlbumRequest) GetAlbumId() string { + if x != nil { + return x.AlbumId + } + return "" +} + +type ResyncAlbumResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + FilesSynced int32 `protobuf:"varint,1,opt,name=files_synced,json=filesSynced,proto3" json:"files_synced,omitempty"` + FilesEnriched int32 `protobuf:"varint,2,opt,name=files_enriched,json=filesEnriched,proto3" json:"files_enriched,omitempty"` + BytesSynced uint64 `protobuf:"varint,3,opt,name=bytes_synced,json=bytesSynced,proto3" json:"bytes_synced,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResyncAlbumResponse) Reset() { + *x = ResyncAlbumResponse{} + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResyncAlbumResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResyncAlbumResponse) ProtoMessage() {} + +func (x *ResyncAlbumResponse) ProtoReflect() protoreflect.Message { + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ResyncAlbumResponse.ProtoReflect.Descriptor instead. +func (*ResyncAlbumResponse) Descriptor() ([]byte, []int) { + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{1} +} + +func (x *ResyncAlbumResponse) GetFilesSynced() int32 { + if x != nil { + return x.FilesSynced + } + return 0 +} + +func (x *ResyncAlbumResponse) GetFilesEnriched() int32 { + if x != nil { + return x.FilesEnriched + } + return 0 +} + +func (x *ResyncAlbumResponse) GetBytesSynced() uint64 { + if x != nil { + return x.BytesSynced + } + return 0 +} + type MonitorAlbumRequest struct { state protoimpl.MessageState `protogen:"open.v1"` AlbumId string `protobuf:"bytes,1,opt,name=album_id,json=albumId,proto3" json:"album_id,omitempty"` @@ -301,7 +405,7 @@ type MonitorAlbumRequest struct { func (x *MonitorAlbumRequest) Reset() { *x = MonitorAlbumRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[0] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -313,7 +417,7 @@ func (x *MonitorAlbumRequest) String() string { func (*MonitorAlbumRequest) ProtoMessage() {} func (x *MonitorAlbumRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[0] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -326,7 +430,7 @@ func (x *MonitorAlbumRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorAlbumRequest.ProtoReflect.Descriptor instead. func (*MonitorAlbumRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{0} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{2} } func (x *MonitorAlbumRequest) GetAlbumId() string { @@ -359,7 +463,7 @@ type IndexerOptions struct { func (x *IndexerOptions) Reset() { *x = IndexerOptions{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[1] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -371,7 +475,7 @@ func (x *IndexerOptions) String() string { func (*IndexerOptions) ProtoMessage() {} func (x *IndexerOptions) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[1] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -384,7 +488,7 @@ func (x *IndexerOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexerOptions.ProtoReflect.Descriptor instead. func (*IndexerOptions) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{1} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{3} } func (x *IndexerOptions) GetTracker() string { @@ -405,7 +509,7 @@ type MonitorAlbumResponse struct { func (x *MonitorAlbumResponse) Reset() { *x = MonitorAlbumResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[2] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -417,7 +521,7 @@ func (x *MonitorAlbumResponse) String() string { func (*MonitorAlbumResponse) ProtoMessage() {} func (x *MonitorAlbumResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[2] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -430,7 +534,7 @@ func (x *MonitorAlbumResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorAlbumResponse.ProtoReflect.Descriptor instead. func (*MonitorAlbumResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{2} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{4} } func (x *MonitorAlbumResponse) GetAlbum() *AlbumDetail { @@ -462,7 +566,7 @@ type GetArtistsRequest struct { func (x *GetArtistsRequest) Reset() { *x = GetArtistsRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[3] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -474,7 +578,7 @@ func (x *GetArtistsRequest) String() string { func (*GetArtistsRequest) ProtoMessage() {} func (x *GetArtistsRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[3] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -487,7 +591,7 @@ func (x *GetArtistsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetArtistsRequest.ProtoReflect.Descriptor instead. func (*GetArtistsRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{3} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{5} } type GetArtistsResponse struct { @@ -499,7 +603,7 @@ type GetArtistsResponse struct { func (x *GetArtistsResponse) Reset() { *x = GetArtistsResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[4] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -511,7 +615,7 @@ func (x *GetArtistsResponse) String() string { func (*GetArtistsResponse) ProtoMessage() {} func (x *GetArtistsResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[4] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -524,7 +628,7 @@ func (x *GetArtistsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetArtistsResponse.ProtoReflect.Descriptor instead. func (*GetArtistsResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{4} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{6} } func (x *GetArtistsResponse) GetArtists() []*ArtistSummary { @@ -551,7 +655,7 @@ type ArtistSummary struct { func (x *ArtistSummary) Reset() { *x = ArtistSummary{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[5] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -563,7 +667,7 @@ func (x *ArtistSummary) String() string { func (*ArtistSummary) ProtoMessage() {} func (x *ArtistSummary) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[5] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -576,7 +680,7 @@ func (x *ArtistSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use ArtistSummary.ProtoReflect.Descriptor instead. func (*ArtistSummary) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{5} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{7} } func (x *ArtistSummary) GetId() string { @@ -663,7 +767,7 @@ type AlbumDetail struct { func (x *AlbumDetail) Reset() { *x = AlbumDetail{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[6] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -675,7 +779,7 @@ func (x *AlbumDetail) String() string { func (*AlbumDetail) ProtoMessage() {} func (x *AlbumDetail) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[6] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -688,7 +792,7 @@ func (x *AlbumDetail) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumDetail.ProtoReflect.Descriptor instead. func (*AlbumDetail) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{6} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{8} } func (x *AlbumDetail) GetId() string { @@ -794,7 +898,7 @@ type DownloadInfo struct { func (x *DownloadInfo) Reset() { *x = DownloadInfo{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[7] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -806,7 +910,7 @@ func (x *DownloadInfo) String() string { func (*DownloadInfo) ProtoMessage() {} func (x *DownloadInfo) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[7] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -819,7 +923,7 @@ func (x *DownloadInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use DownloadInfo.ProtoReflect.Descriptor instead. func (*DownloadInfo) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{7} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{9} } func (x *DownloadInfo) GetState() string { @@ -859,7 +963,7 @@ type GetAlbumRequest struct { func (x *GetAlbumRequest) Reset() { *x = GetAlbumRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[8] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -871,7 +975,7 @@ func (x *GetAlbumRequest) String() string { func (*GetAlbumRequest) ProtoMessage() {} func (x *GetAlbumRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[8] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -884,7 +988,7 @@ func (x *GetAlbumRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAlbumRequest.ProtoReflect.Descriptor instead. func (*GetAlbumRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{8} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{10} } func (x *GetAlbumRequest) GetAlbumId() string { @@ -904,7 +1008,7 @@ type AlbumInfo struct { func (x *AlbumInfo) Reset() { *x = AlbumInfo{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[9] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -916,7 +1020,7 @@ func (x *AlbumInfo) String() string { func (*AlbumInfo) ProtoMessage() {} func (x *AlbumInfo) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[9] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -929,7 +1033,7 @@ func (x *AlbumInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumInfo.ProtoReflect.Descriptor instead. func (*AlbumInfo) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{9} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{11} } func (x *AlbumInfo) GetAlbum() *AlbumDetail { @@ -955,7 +1059,7 @@ type GetAlbumResponse struct { func (x *GetAlbumResponse) Reset() { *x = GetAlbumResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[10] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -967,7 +1071,7 @@ func (x *GetAlbumResponse) String() string { func (*GetAlbumResponse) ProtoMessage() {} func (x *GetAlbumResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[10] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -980,7 +1084,7 @@ func (x *GetAlbumResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAlbumResponse.ProtoReflect.Descriptor instead. func (*GetAlbumResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{10} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{12} } func (x *GetAlbumResponse) GetInfo() *AlbumInfo { @@ -999,7 +1103,7 @@ type AnalyzeAlbumReleaseRequest struct { func (x *AnalyzeAlbumReleaseRequest) Reset() { *x = AnalyzeAlbumReleaseRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[11] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1011,7 +1115,7 @@ func (x *AnalyzeAlbumReleaseRequest) String() string { func (*AnalyzeAlbumReleaseRequest) ProtoMessage() {} func (x *AnalyzeAlbumReleaseRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[11] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1024,7 +1128,7 @@ func (x *AnalyzeAlbumReleaseRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeAlbumReleaseRequest.ProtoReflect.Descriptor instead. func (*AnalyzeAlbumReleaseRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{11} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{13} } func (x *AnalyzeAlbumReleaseRequest) GetAlbumId() string { @@ -1043,7 +1147,7 @@ type AnalyzeAlbumReleaseResponse struct { func (x *AnalyzeAlbumReleaseResponse) Reset() { *x = AnalyzeAlbumReleaseResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[12] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1055,7 +1159,7 @@ func (x *AnalyzeAlbumReleaseResponse) String() string { func (*AnalyzeAlbumReleaseResponse) ProtoMessage() {} func (x *AnalyzeAlbumReleaseResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[12] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1068,7 +1172,7 @@ func (x *AnalyzeAlbumReleaseResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AnalyzeAlbumReleaseResponse.ProtoReflect.Descriptor instead. func (*AnalyzeAlbumReleaseResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{12} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{14} } func (x *AnalyzeAlbumReleaseResponse) GetInfo() *AlbumInfo { @@ -1102,7 +1206,7 @@ type TrackDetail struct { func (x *TrackDetail) Reset() { *x = TrackDetail{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[13] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1114,7 +1218,7 @@ func (x *TrackDetail) String() string { func (*TrackDetail) ProtoMessage() {} func (x *TrackDetail) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[13] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1127,7 +1231,7 @@ func (x *TrackDetail) ProtoReflect() protoreflect.Message { // Deprecated: Use TrackDetail.ProtoReflect.Descriptor instead. func (*TrackDetail) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{13} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{15} } func (x *TrackDetail) GetId() string { @@ -1252,7 +1356,7 @@ type ArtistCredit struct { func (x *ArtistCredit) Reset() { *x = ArtistCredit{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[14] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1264,7 +1368,7 @@ func (x *ArtistCredit) String() string { func (*ArtistCredit) ProtoMessage() {} func (x *ArtistCredit) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[14] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1277,7 +1381,7 @@ func (x *ArtistCredit) ProtoReflect() protoreflect.Message { // Deprecated: Use ArtistCredit.ProtoReflect.Descriptor instead. func (*ArtistCredit) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{14} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{16} } func (x *ArtistCredit) GetId() string { @@ -1316,7 +1420,7 @@ type AlbumReleaseDetail struct { func (x *AlbumReleaseDetail) Reset() { *x = AlbumReleaseDetail{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[15] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1328,7 +1432,7 @@ func (x *AlbumReleaseDetail) String() string { func (*AlbumReleaseDetail) ProtoMessage() {} func (x *AlbumReleaseDetail) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[15] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1341,7 +1445,7 @@ func (x *AlbumReleaseDetail) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumReleaseDetail.ProtoReflect.Descriptor instead. func (*AlbumReleaseDetail) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{15} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{17} } func (x *AlbumReleaseDetail) GetId() string { @@ -1468,7 +1572,7 @@ type MonitoredRelease struct { func (x *MonitoredRelease) Reset() { *x = MonitoredRelease{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[16] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1480,7 +1584,7 @@ func (x *MonitoredRelease) String() string { func (*MonitoredRelease) ProtoMessage() {} func (x *MonitoredRelease) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[16] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1493,7 +1597,7 @@ func (x *MonitoredRelease) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitoredRelease.ProtoReflect.Descriptor instead. func (*MonitoredRelease) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{16} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{18} } func (x *MonitoredRelease) GetInfoHash() string { @@ -1633,7 +1737,7 @@ type SearchArtistsRequest struct { func (x *SearchArtistsRequest) Reset() { *x = SearchArtistsRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[17] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1645,7 +1749,7 @@ func (x *SearchArtistsRequest) String() string { func (*SearchArtistsRequest) ProtoMessage() {} func (x *SearchArtistsRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[17] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1658,7 +1762,7 @@ func (x *SearchArtistsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchArtistsRequest.ProtoReflect.Descriptor instead. func (*SearchArtistsRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{17} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{19} } func (x *SearchArtistsRequest) GetQuery() string { @@ -1692,7 +1796,7 @@ type SearchArtistsResponse struct { func (x *SearchArtistsResponse) Reset() { *x = SearchArtistsResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[18] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1704,7 +1808,7 @@ func (x *SearchArtistsResponse) String() string { func (*SearchArtistsResponse) ProtoMessage() {} func (x *SearchArtistsResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[18] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1717,7 +1821,7 @@ func (x *SearchArtistsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchArtistsResponse.ProtoReflect.Descriptor instead. func (*SearchArtistsResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{18} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{20} } func (x *SearchArtistsResponse) GetArtists() []*SearchArtistResult { @@ -1753,7 +1857,7 @@ type SearchArtistResult struct { func (x *SearchArtistResult) Reset() { *x = SearchArtistResult{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[19] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1765,7 +1869,7 @@ func (x *SearchArtistResult) String() string { func (*SearchArtistResult) ProtoMessage() {} func (x *SearchArtistResult) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[19] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1778,7 +1882,7 @@ func (x *SearchArtistResult) ProtoReflect() protoreflect.Message { // Deprecated: Use SearchArtistResult.ProtoReflect.Descriptor instead. func (*SearchArtistResult) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{19} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{21} } func (x *SearchArtistResult) GetId() string { @@ -1868,7 +1972,7 @@ type ExternalId struct { func (x *ExternalId) Reset() { *x = ExternalId{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[20] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1880,7 +1984,7 @@ func (x *ExternalId) String() string { func (*ExternalId) ProtoMessage() {} func (x *ExternalId) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[20] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1893,7 +1997,7 @@ func (x *ExternalId) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalId.ProtoReflect.Descriptor instead. func (*ExternalId) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{20} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{22} } func (x *ExternalId) GetProvider() string { @@ -1921,7 +2025,7 @@ type GetArtistAlbumsRequest struct { func (x *GetArtistAlbumsRequest) Reset() { *x = GetArtistAlbumsRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[21] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1933,7 +2037,7 @@ func (x *GetArtistAlbumsRequest) String() string { func (*GetArtistAlbumsRequest) ProtoMessage() {} func (x *GetArtistAlbumsRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[21] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1946,7 +2050,7 @@ func (x *GetArtistAlbumsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetArtistAlbumsRequest.ProtoReflect.Descriptor instead. func (*GetArtistAlbumsRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{21} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{23} } func (x *GetArtistAlbumsRequest) GetArtistId() string { @@ -1980,7 +2084,7 @@ type GetArtistAlbumsResponse struct { func (x *GetArtistAlbumsResponse) Reset() { *x = GetArtistAlbumsResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[22] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1992,7 +2096,7 @@ func (x *GetArtistAlbumsResponse) String() string { func (*GetArtistAlbumsResponse) ProtoMessage() {} func (x *GetArtistAlbumsResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[22] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2005,7 +2109,7 @@ func (x *GetArtistAlbumsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetArtistAlbumsResponse.ProtoReflect.Descriptor instead. func (*GetArtistAlbumsResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{22} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{24} } func (x *GetArtistAlbumsResponse) GetAlbums() []*AlbumResult { @@ -2042,7 +2146,7 @@ type AlbumResult struct { func (x *AlbumResult) Reset() { *x = AlbumResult{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[23] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2054,7 +2158,7 @@ func (x *AlbumResult) String() string { func (*AlbumResult) ProtoMessage() {} func (x *AlbumResult) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[23] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2067,7 +2171,7 @@ func (x *AlbumResult) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumResult.ProtoReflect.Descriptor instead. func (*AlbumResult) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{23} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{25} } func (x *AlbumResult) GetId() string { @@ -2165,7 +2269,7 @@ type AlbumArtistCredit struct { func (x *AlbumArtistCredit) Reset() { *x = AlbumArtistCredit{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[24] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2177,7 +2281,7 @@ func (x *AlbumArtistCredit) String() string { func (*AlbumArtistCredit) ProtoMessage() {} func (x *AlbumArtistCredit) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[24] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2190,7 +2294,7 @@ func (x *AlbumArtistCredit) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumArtistCredit.ProtoReflect.Descriptor instead. func (*AlbumArtistCredit) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{24} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{26} } func (x *AlbumArtistCredit) GetId() string { @@ -2225,7 +2329,7 @@ type AlbumLabel struct { func (x *AlbumLabel) Reset() { *x = AlbumLabel{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[25] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2237,7 +2341,7 @@ func (x *AlbumLabel) String() string { func (*AlbumLabel) ProtoMessage() {} func (x *AlbumLabel) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[25] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2250,7 +2354,7 @@ func (x *AlbumLabel) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumLabel.ProtoReflect.Descriptor instead. func (*AlbumLabel) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{25} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{27} } func (x *AlbumLabel) GetId() string { @@ -2283,7 +2387,7 @@ type SubscribeEventsRequest struct { func (x *SubscribeEventsRequest) Reset() { *x = SubscribeEventsRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[26] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2295,7 +2399,7 @@ func (x *SubscribeEventsRequest) String() string { func (*SubscribeEventsRequest) ProtoMessage() {} func (x *SubscribeEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[26] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2308,7 +2412,7 @@ func (x *SubscribeEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubscribeEventsRequest.ProtoReflect.Descriptor instead. func (*SubscribeEventsRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{26} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{28} } func (x *SubscribeEventsRequest) GetSinceSeq() int64 { @@ -2335,7 +2439,7 @@ type AlbumEvent struct { func (x *AlbumEvent) Reset() { *x = AlbumEvent{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[27] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2347,7 +2451,7 @@ func (x *AlbumEvent) String() string { func (*AlbumEvent) ProtoMessage() {} func (x *AlbumEvent) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[27] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2360,7 +2464,7 @@ func (x *AlbumEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use AlbumEvent.ProtoReflect.Descriptor instead. func (*AlbumEvent) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{27} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{29} } func (x *AlbumEvent) GetSeq() int64 { @@ -2440,7 +2544,7 @@ type MonitorAlbumStreamRequest struct { func (x *MonitorAlbumStreamRequest) Reset() { *x = MonitorAlbumStreamRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[28] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2452,7 +2556,7 @@ func (x *MonitorAlbumStreamRequest) String() string { func (*MonitorAlbumStreamRequest) ProtoMessage() {} func (x *MonitorAlbumStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[28] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2465,7 +2569,7 @@ func (x *MonitorAlbumStreamRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorAlbumStreamRequest.ProtoReflect.Descriptor instead. func (*MonitorAlbumStreamRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{28} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{30} } func (x *MonitorAlbumStreamRequest) GetMessage() isMonitorAlbumStreamRequest_Message { @@ -2536,7 +2640,7 @@ type StartMonitorRequest struct { func (x *StartMonitorRequest) Reset() { *x = StartMonitorRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[29] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2548,7 +2652,7 @@ func (x *StartMonitorRequest) String() string { func (*StartMonitorRequest) ProtoMessage() {} func (x *StartMonitorRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[29] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2561,7 +2665,7 @@ func (x *StartMonitorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartMonitorRequest.ProtoReflect.Descriptor instead. func (*StartMonitorRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{29} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{31} } func (x *StartMonitorRequest) GetAlbumId() string { @@ -2607,7 +2711,7 @@ type UserDecision struct { func (x *UserDecision) Reset() { *x = UserDecision{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[30] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2619,7 +2723,7 @@ func (x *UserDecision) String() string { func (*UserDecision) ProtoMessage() {} func (x *UserDecision) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[30] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2632,7 +2736,7 @@ func (x *UserDecision) ProtoReflect() protoreflect.Message { // Deprecated: Use UserDecision.ProtoReflect.Descriptor instead. func (*UserDecision) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{30} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{32} } func (x *UserDecision) GetPromptId() string { @@ -2707,7 +2811,7 @@ type SelectedIds struct { func (x *SelectedIds) Reset() { *x = SelectedIds{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[31] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2719,7 +2823,7 @@ func (x *SelectedIds) String() string { func (*SelectedIds) ProtoMessage() {} func (x *SelectedIds) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[31] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2732,7 +2836,7 @@ func (x *SelectedIds) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectedIds.ProtoReflect.Descriptor instead. func (*SelectedIds) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{31} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{33} } func (x *SelectedIds) GetIds() []string { @@ -2750,7 +2854,7 @@ type CancelRequest struct { func (x *CancelRequest) Reset() { *x = CancelRequest{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[32] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2762,7 +2866,7 @@ func (x *CancelRequest) String() string { func (*CancelRequest) ProtoMessage() {} func (x *CancelRequest) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[32] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2775,7 +2879,7 @@ func (x *CancelRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelRequest.ProtoReflect.Descriptor instead. func (*CancelRequest) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{32} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{34} } type MonitorAlbumStreamResponse struct { @@ -2793,7 +2897,7 @@ type MonitorAlbumStreamResponse struct { func (x *MonitorAlbumStreamResponse) Reset() { *x = MonitorAlbumStreamResponse{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[33] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2805,7 +2909,7 @@ func (x *MonitorAlbumStreamResponse) String() string { func (*MonitorAlbumStreamResponse) ProtoMessage() {} func (x *MonitorAlbumStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[33] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2818,7 +2922,7 @@ func (x *MonitorAlbumStreamResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MonitorAlbumStreamResponse.ProtoReflect.Descriptor instead. func (*MonitorAlbumStreamResponse) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{33} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{35} } func (x *MonitorAlbumStreamResponse) GetMessage() isMonitorAlbumStreamResponse_Message { @@ -2908,7 +3012,7 @@ type StatusUpdate struct { func (x *StatusUpdate) Reset() { *x = StatusUpdate{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[34] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2920,7 +3024,7 @@ func (x *StatusUpdate) String() string { func (*StatusUpdate) ProtoMessage() {} func (x *StatusUpdate) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[34] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2933,7 +3037,7 @@ func (x *StatusUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusUpdate.ProtoReflect.Descriptor instead. func (*StatusUpdate) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{34} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{36} } func (x *StatusUpdate) GetStep() MonitorStep { @@ -3024,7 +3128,7 @@ type PromptForDecision struct { func (x *PromptForDecision) Reset() { *x = PromptForDecision{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[35] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3036,7 +3140,7 @@ func (x *PromptForDecision) String() string { func (*PromptForDecision) ProtoMessage() {} func (x *PromptForDecision) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[35] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3049,7 +3153,7 @@ func (x *PromptForDecision) ProtoReflect() protoreflect.Message { // Deprecated: Use PromptForDecision.ProtoReflect.Descriptor instead. func (*PromptForDecision) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{35} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{37} } func (x *PromptForDecision) GetPromptId() string { @@ -3147,7 +3251,7 @@ type ErrorUpdate struct { func (x *ErrorUpdate) Reset() { *x = ErrorUpdate{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[36] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3159,7 +3263,7 @@ func (x *ErrorUpdate) String() string { func (*ErrorUpdate) ProtoMessage() {} func (x *ErrorUpdate) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[36] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3172,7 +3276,7 @@ func (x *ErrorUpdate) ProtoReflect() protoreflect.Message { // Deprecated: Use ErrorUpdate.ProtoReflect.Descriptor instead. func (*ErrorUpdate) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{36} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{38} } func (x *ErrorUpdate) GetFailedStep() MonitorStep { @@ -3209,7 +3313,7 @@ type StreamAlbumInfo struct { func (x *StreamAlbumInfo) Reset() { *x = StreamAlbumInfo{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[37] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3221,7 +3325,7 @@ func (x *StreamAlbumInfo) String() string { func (*StreamAlbumInfo) ProtoMessage() {} func (x *StreamAlbumInfo) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[37] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3234,7 +3338,7 @@ func (x *StreamAlbumInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use StreamAlbumInfo.ProtoReflect.Descriptor instead. func (*StreamAlbumInfo) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{37} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{39} } func (x *StreamAlbumInfo) GetArtist() string { @@ -3281,7 +3385,7 @@ type TorrentList struct { func (x *TorrentList) Reset() { *x = TorrentList{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[38] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3293,7 +3397,7 @@ func (x *TorrentList) String() string { func (*TorrentList) ProtoMessage() {} func (x *TorrentList) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[38] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3306,7 +3410,7 @@ func (x *TorrentList) ProtoReflect() protoreflect.Message { // Deprecated: Use TorrentList.ProtoReflect.Descriptor instead. func (*TorrentList) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{38} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{40} } func (x *TorrentList) GetTorrents() []*TorrentSummary { @@ -3330,7 +3434,7 @@ type TorrentSummary struct { func (x *TorrentSummary) Reset() { *x = TorrentSummary{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[39] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3342,7 +3446,7 @@ func (x *TorrentSummary) String() string { func (*TorrentSummary) ProtoMessage() {} func (x *TorrentSummary) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[39] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3355,7 +3459,7 @@ func (x *TorrentSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use TorrentSummary.ProtoReflect.Descriptor instead. func (*TorrentSummary) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{39} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{41} } func (x *TorrentSummary) GetId() string { @@ -3414,7 +3518,7 @@ type ReleaseInfo struct { func (x *ReleaseInfo) Reset() { *x = ReleaseInfo{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[40] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3426,7 +3530,7 @@ func (x *ReleaseInfo) String() string { func (*ReleaseInfo) ProtoMessage() {} func (x *ReleaseInfo) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[40] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3439,7 +3543,7 @@ func (x *ReleaseInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ReleaseInfo.ProtoReflect.Descriptor instead. func (*ReleaseInfo) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{40} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{42} } func (x *ReleaseInfo) GetInfoHash() string { @@ -3495,7 +3599,7 @@ type ConfirmPrompt struct { func (x *ConfirmPrompt) Reset() { *x = ConfirmPrompt{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[41] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3507,7 +3611,7 @@ func (x *ConfirmPrompt) String() string { func (*ConfirmPrompt) ProtoMessage() {} func (x *ConfirmPrompt) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[41] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3520,7 +3624,7 @@ func (x *ConfirmPrompt) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfirmPrompt.ProtoReflect.Descriptor instead. func (*ConfirmPrompt) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{41} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{43} } func (x *ConfirmPrompt) GetConfirmLabel() string { @@ -3554,7 +3658,7 @@ type SelectOnePrompt struct { func (x *SelectOnePrompt) Reset() { *x = SelectOnePrompt{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[42] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3566,7 +3670,7 @@ func (x *SelectOnePrompt) String() string { func (*SelectOnePrompt) ProtoMessage() {} func (x *SelectOnePrompt) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[42] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3579,7 +3683,7 @@ func (x *SelectOnePrompt) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectOnePrompt.ProtoReflect.Descriptor instead. func (*SelectOnePrompt) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{42} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{44} } func (x *SelectOnePrompt) GetOptions() []*SelectOption { @@ -3608,7 +3712,7 @@ type SelectManyPrompt struct { func (x *SelectManyPrompt) Reset() { *x = SelectManyPrompt{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[43] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3620,7 +3724,7 @@ func (x *SelectManyPrompt) String() string { func (*SelectManyPrompt) ProtoMessage() {} func (x *SelectManyPrompt) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[43] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3633,7 +3737,7 @@ func (x *SelectManyPrompt) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectManyPrompt.ProtoReflect.Descriptor instead. func (*SelectManyPrompt) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{43} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{45} } func (x *SelectManyPrompt) GetOptions() []*SelectOption { @@ -3675,7 +3779,7 @@ type SelectOption struct { func (x *SelectOption) Reset() { *x = SelectOption{} - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[44] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3687,7 +3791,7 @@ func (x *SelectOption) String() string { func (*SelectOption) ProtoMessage() {} func (x *SelectOption) ProtoReflect() protoreflect.Message { - mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[44] + mi := &file_music_agregator_v1_music_agregator_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3700,7 +3804,7 @@ func (x *SelectOption) ProtoReflect() protoreflect.Message { // Deprecated: Use SelectOption.ProtoReflect.Descriptor instead. func (*SelectOption) Descriptor() ([]byte, []int) { - return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{44} + return file_music_agregator_v1_music_agregator_proto_rawDescGZIP(), []int{46} } func (x *SelectOption) GetId() string { @@ -3728,7 +3832,13 @@ var File_music_agregator_v1_music_agregator_proto protoreflect.FileDescriptor const file_music_agregator_v1_music_agregator_proto_rawDesc = "" + "\n" + - "(music_agregator/v1/music_agregator.proto\x12\x12music_agregator.v1\"\xb8\x01\n" + + "(music_agregator/v1/music_agregator.proto\x12\x12music_agregator.v1\"/\n" + + "\x12ResyncAlbumRequest\x12\x19\n" + + "\balbum_id\x18\x01 \x01(\tR\aalbumId\"\x82\x01\n" + + "\x13ResyncAlbumResponse\x12!\n" + + "\ffiles_synced\x18\x01 \x01(\x05R\vfilesSynced\x12%\n" + + "\x0efiles_enriched\x18\x02 \x01(\x05R\rfilesEnriched\x12!\n" + + "\fbytes_synced\x18\x03 \x01(\x04R\vbytesSynced\"\xb8\x01\n" + "\x13MonitorAlbumRequest\x12\x19\n" + "\balbum_id\x18\x01 \x01(\tR\aalbumId\x12K\n" + "\x0findexer_options\x18\x02 \x01(\v2\".music_agregator.v1.IndexerOptionsR\x0eindexerOptions\x129\n" + @@ -4050,7 +4160,7 @@ const file_music_agregator_v1_music_agregator_proto_rawDesc = "" + "\x17PROMPT_TYPE_UNSPECIFIED\x10\x00\x12\x17\n" + "\x13PROMPT_TYPE_CONFIRM\x10\x01\x12\x1a\n" + "\x16PROMPT_TYPE_SELECT_ONE\x10\x02\x12\x1b\n" + - "\x17PROMPT_TYPE_SELECT_MANY\x10\x032\xe5\x06\n" + + "\x17PROMPT_TYPE_SELECT_MANY\x10\x032\xc7\a\n" + "\x15MusicAgregatorService\x12f\n" + "\fMonitorAlbum\x12'.music_agregator.v1.MonitorAlbumRequest\x1a(.music_agregator.v1.MonitorAlbumResponse\"\x03\x88\x02\x01\x12y\n" + "\x12MonitorAlbumStream\x12-.music_agregator.v1.MonitorAlbumStreamRequest\x1a..music_agregator.v1.MonitorAlbumStreamResponse\"\x00(\x010\x01\x12]\n" + @@ -4060,7 +4170,8 @@ const file_music_agregator_v1_music_agregator_proto_rawDesc = "" + "\x13AnalyzeAlbumRelease\x12..music_agregator.v1.AnalyzeAlbumReleaseRequest\x1a/.music_agregator.v1.AnalyzeAlbumReleaseResponse\"\x00\x12f\n" + "\rSearchArtists\x12(.music_agregator.v1.SearchArtistsRequest\x1a).music_agregator.v1.SearchArtistsResponse\"\x00\x12l\n" + "\x0fGetArtistAlbums\x12*.music_agregator.v1.GetArtistAlbumsRequest\x1a+.music_agregator.v1.GetArtistAlbumsResponse\"\x00\x12a\n" + - "\x0fSubscribeEvents\x12*.music_agregator.v1.SubscribeEventsRequest\x1a\x1e.music_agregator.v1.AlbumEvent\"\x000\x01B5Z3homelab.lan/music-agregator/gen/music_agregator/v1/b\x06proto3" + "\x0fSubscribeEvents\x12*.music_agregator.v1.SubscribeEventsRequest\x1a\x1e.music_agregator.v1.AlbumEvent\"\x000\x01\x12`\n" + + "\vResyncAlbum\x12&.music_agregator.v1.ResyncAlbumRequest\x1a'.music_agregator.v1.ResyncAlbumResponse\"\x00B5Z3homelab.lan/music-agregator/gen/music_agregator/v1/b\x06proto3" var ( file_music_agregator_v1_music_agregator_proto_rawDescOnce sync.Once @@ -4075,123 +4186,127 @@ func file_music_agregator_v1_music_agregator_proto_rawDescGZIP() []byte { } var file_music_agregator_v1_music_agregator_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_music_agregator_v1_music_agregator_proto_msgTypes = make([]protoimpl.MessageInfo, 45) +var file_music_agregator_v1_music_agregator_proto_msgTypes = make([]protoimpl.MessageInfo, 47) var file_music_agregator_v1_music_agregator_proto_goTypes = []any{ (QualityType)(0), // 0: music_agregator.v1.QualityType (MonitorState)(0), // 1: music_agregator.v1.MonitorState (InteractionMode)(0), // 2: music_agregator.v1.InteractionMode (MonitorStep)(0), // 3: music_agregator.v1.MonitorStep (PromptType)(0), // 4: music_agregator.v1.PromptType - (*MonitorAlbumRequest)(nil), // 5: music_agregator.v1.MonitorAlbumRequest - (*IndexerOptions)(nil), // 6: music_agregator.v1.IndexerOptions - (*MonitorAlbumResponse)(nil), // 7: music_agregator.v1.MonitorAlbumResponse - (*GetArtistsRequest)(nil), // 8: music_agregator.v1.GetArtistsRequest - (*GetArtistsResponse)(nil), // 9: music_agregator.v1.GetArtistsResponse - (*ArtistSummary)(nil), // 10: music_agregator.v1.ArtistSummary - (*AlbumDetail)(nil), // 11: music_agregator.v1.AlbumDetail - (*DownloadInfo)(nil), // 12: music_agregator.v1.DownloadInfo - (*GetAlbumRequest)(nil), // 13: music_agregator.v1.GetAlbumRequest - (*AlbumInfo)(nil), // 14: music_agregator.v1.AlbumInfo - (*GetAlbumResponse)(nil), // 15: music_agregator.v1.GetAlbumResponse - (*AnalyzeAlbumReleaseRequest)(nil), // 16: music_agregator.v1.AnalyzeAlbumReleaseRequest - (*AnalyzeAlbumReleaseResponse)(nil), // 17: music_agregator.v1.AnalyzeAlbumReleaseResponse - (*TrackDetail)(nil), // 18: music_agregator.v1.TrackDetail - (*ArtistCredit)(nil), // 19: music_agregator.v1.ArtistCredit - (*AlbumReleaseDetail)(nil), // 20: music_agregator.v1.AlbumReleaseDetail - (*MonitoredRelease)(nil), // 21: music_agregator.v1.MonitoredRelease - (*SearchArtistsRequest)(nil), // 22: music_agregator.v1.SearchArtistsRequest - (*SearchArtistsResponse)(nil), // 23: music_agregator.v1.SearchArtistsResponse - (*SearchArtistResult)(nil), // 24: music_agregator.v1.SearchArtistResult - (*ExternalId)(nil), // 25: music_agregator.v1.ExternalId - (*GetArtistAlbumsRequest)(nil), // 26: music_agregator.v1.GetArtistAlbumsRequest - (*GetArtistAlbumsResponse)(nil), // 27: music_agregator.v1.GetArtistAlbumsResponse - (*AlbumResult)(nil), // 28: music_agregator.v1.AlbumResult - (*AlbumArtistCredit)(nil), // 29: music_agregator.v1.AlbumArtistCredit - (*AlbumLabel)(nil), // 30: music_agregator.v1.AlbumLabel - (*SubscribeEventsRequest)(nil), // 31: music_agregator.v1.SubscribeEventsRequest - (*AlbumEvent)(nil), // 32: music_agregator.v1.AlbumEvent - (*MonitorAlbumStreamRequest)(nil), // 33: music_agregator.v1.MonitorAlbumStreamRequest - (*StartMonitorRequest)(nil), // 34: music_agregator.v1.StartMonitorRequest - (*UserDecision)(nil), // 35: music_agregator.v1.UserDecision - (*SelectedIds)(nil), // 36: music_agregator.v1.SelectedIds - (*CancelRequest)(nil), // 37: music_agregator.v1.CancelRequest - (*MonitorAlbumStreamResponse)(nil), // 38: music_agregator.v1.MonitorAlbumStreamResponse - (*StatusUpdate)(nil), // 39: music_agregator.v1.StatusUpdate - (*PromptForDecision)(nil), // 40: music_agregator.v1.PromptForDecision - (*ErrorUpdate)(nil), // 41: music_agregator.v1.ErrorUpdate - (*StreamAlbumInfo)(nil), // 42: music_agregator.v1.StreamAlbumInfo - (*TorrentList)(nil), // 43: music_agregator.v1.TorrentList - (*TorrentSummary)(nil), // 44: music_agregator.v1.TorrentSummary - (*ReleaseInfo)(nil), // 45: music_agregator.v1.ReleaseInfo - (*ConfirmPrompt)(nil), // 46: music_agregator.v1.ConfirmPrompt - (*SelectOnePrompt)(nil), // 47: music_agregator.v1.SelectOnePrompt - (*SelectManyPrompt)(nil), // 48: music_agregator.v1.SelectManyPrompt - (*SelectOption)(nil), // 49: music_agregator.v1.SelectOption + (*ResyncAlbumRequest)(nil), // 5: music_agregator.v1.ResyncAlbumRequest + (*ResyncAlbumResponse)(nil), // 6: music_agregator.v1.ResyncAlbumResponse + (*MonitorAlbumRequest)(nil), // 7: music_agregator.v1.MonitorAlbumRequest + (*IndexerOptions)(nil), // 8: music_agregator.v1.IndexerOptions + (*MonitorAlbumResponse)(nil), // 9: music_agregator.v1.MonitorAlbumResponse + (*GetArtistsRequest)(nil), // 10: music_agregator.v1.GetArtistsRequest + (*GetArtistsResponse)(nil), // 11: music_agregator.v1.GetArtistsResponse + (*ArtistSummary)(nil), // 12: music_agregator.v1.ArtistSummary + (*AlbumDetail)(nil), // 13: music_agregator.v1.AlbumDetail + (*DownloadInfo)(nil), // 14: music_agregator.v1.DownloadInfo + (*GetAlbumRequest)(nil), // 15: music_agregator.v1.GetAlbumRequest + (*AlbumInfo)(nil), // 16: music_agregator.v1.AlbumInfo + (*GetAlbumResponse)(nil), // 17: music_agregator.v1.GetAlbumResponse + (*AnalyzeAlbumReleaseRequest)(nil), // 18: music_agregator.v1.AnalyzeAlbumReleaseRequest + (*AnalyzeAlbumReleaseResponse)(nil), // 19: music_agregator.v1.AnalyzeAlbumReleaseResponse + (*TrackDetail)(nil), // 20: music_agregator.v1.TrackDetail + (*ArtistCredit)(nil), // 21: music_agregator.v1.ArtistCredit + (*AlbumReleaseDetail)(nil), // 22: music_agregator.v1.AlbumReleaseDetail + (*MonitoredRelease)(nil), // 23: music_agregator.v1.MonitoredRelease + (*SearchArtistsRequest)(nil), // 24: music_agregator.v1.SearchArtistsRequest + (*SearchArtistsResponse)(nil), // 25: music_agregator.v1.SearchArtistsResponse + (*SearchArtistResult)(nil), // 26: music_agregator.v1.SearchArtistResult + (*ExternalId)(nil), // 27: music_agregator.v1.ExternalId + (*GetArtistAlbumsRequest)(nil), // 28: music_agregator.v1.GetArtistAlbumsRequest + (*GetArtistAlbumsResponse)(nil), // 29: music_agregator.v1.GetArtistAlbumsResponse + (*AlbumResult)(nil), // 30: music_agregator.v1.AlbumResult + (*AlbumArtistCredit)(nil), // 31: music_agregator.v1.AlbumArtistCredit + (*AlbumLabel)(nil), // 32: music_agregator.v1.AlbumLabel + (*SubscribeEventsRequest)(nil), // 33: music_agregator.v1.SubscribeEventsRequest + (*AlbumEvent)(nil), // 34: music_agregator.v1.AlbumEvent + (*MonitorAlbumStreamRequest)(nil), // 35: music_agregator.v1.MonitorAlbumStreamRequest + (*StartMonitorRequest)(nil), // 36: music_agregator.v1.StartMonitorRequest + (*UserDecision)(nil), // 37: music_agregator.v1.UserDecision + (*SelectedIds)(nil), // 38: music_agregator.v1.SelectedIds + (*CancelRequest)(nil), // 39: music_agregator.v1.CancelRequest + (*MonitorAlbumStreamResponse)(nil), // 40: music_agregator.v1.MonitorAlbumStreamResponse + (*StatusUpdate)(nil), // 41: music_agregator.v1.StatusUpdate + (*PromptForDecision)(nil), // 42: music_agregator.v1.PromptForDecision + (*ErrorUpdate)(nil), // 43: music_agregator.v1.ErrorUpdate + (*StreamAlbumInfo)(nil), // 44: music_agregator.v1.StreamAlbumInfo + (*TorrentList)(nil), // 45: music_agregator.v1.TorrentList + (*TorrentSummary)(nil), // 46: music_agregator.v1.TorrentSummary + (*ReleaseInfo)(nil), // 47: music_agregator.v1.ReleaseInfo + (*ConfirmPrompt)(nil), // 48: music_agregator.v1.ConfirmPrompt + (*SelectOnePrompt)(nil), // 49: music_agregator.v1.SelectOnePrompt + (*SelectManyPrompt)(nil), // 50: music_agregator.v1.SelectManyPrompt + (*SelectOption)(nil), // 51: music_agregator.v1.SelectOption } var file_music_agregator_v1_music_agregator_proto_depIdxs = []int32{ - 6, // 0: music_agregator.v1.MonitorAlbumRequest.indexer_options:type_name -> music_agregator.v1.IndexerOptions + 8, // 0: music_agregator.v1.MonitorAlbumRequest.indexer_options:type_name -> music_agregator.v1.IndexerOptions 0, // 1: music_agregator.v1.MonitorAlbumRequest.quality:type_name -> music_agregator.v1.QualityType - 11, // 2: music_agregator.v1.MonitorAlbumResponse.album:type_name -> music_agregator.v1.AlbumDetail - 10, // 3: music_agregator.v1.MonitorAlbumResponse.artist:type_name -> music_agregator.v1.ArtistSummary - 21, // 4: music_agregator.v1.MonitorAlbumResponse.release:type_name -> music_agregator.v1.MonitoredRelease - 10, // 5: music_agregator.v1.GetArtistsResponse.artists:type_name -> music_agregator.v1.ArtistSummary + 13, // 2: music_agregator.v1.MonitorAlbumResponse.album:type_name -> music_agregator.v1.AlbumDetail + 12, // 3: music_agregator.v1.MonitorAlbumResponse.artist:type_name -> music_agregator.v1.ArtistSummary + 23, // 4: music_agregator.v1.MonitorAlbumResponse.release:type_name -> music_agregator.v1.MonitoredRelease + 12, // 5: music_agregator.v1.GetArtistsResponse.artists:type_name -> music_agregator.v1.ArtistSummary 1, // 6: music_agregator.v1.ArtistSummary.monitor_state:type_name -> music_agregator.v1.MonitorState - 11, // 7: music_agregator.v1.ArtistSummary.albums:type_name -> music_agregator.v1.AlbumDetail + 13, // 7: music_agregator.v1.ArtistSummary.albums:type_name -> music_agregator.v1.AlbumDetail 1, // 8: music_agregator.v1.AlbumDetail.monitor_state:type_name -> music_agregator.v1.MonitorState - 12, // 9: music_agregator.v1.AlbumDetail.downloads:type_name -> music_agregator.v1.DownloadInfo - 20, // 10: music_agregator.v1.AlbumDetail.release:type_name -> music_agregator.v1.AlbumReleaseDetail - 11, // 11: music_agregator.v1.AlbumInfo.album:type_name -> music_agregator.v1.AlbumDetail - 18, // 12: music_agregator.v1.AlbumInfo.tracks:type_name -> music_agregator.v1.TrackDetail - 14, // 13: music_agregator.v1.GetAlbumResponse.info:type_name -> music_agregator.v1.AlbumInfo - 14, // 14: music_agregator.v1.AnalyzeAlbumReleaseResponse.info:type_name -> music_agregator.v1.AlbumInfo - 19, // 15: music_agregator.v1.TrackDetail.artists:type_name -> music_agregator.v1.ArtistCredit - 24, // 16: music_agregator.v1.SearchArtistsResponse.artists:type_name -> music_agregator.v1.SearchArtistResult - 25, // 17: music_agregator.v1.SearchArtistResult.external_ids:type_name -> music_agregator.v1.ExternalId - 28, // 18: music_agregator.v1.GetArtistAlbumsResponse.albums:type_name -> music_agregator.v1.AlbumResult - 29, // 19: music_agregator.v1.AlbumResult.artists:type_name -> music_agregator.v1.AlbumArtistCredit - 30, // 20: music_agregator.v1.AlbumResult.label:type_name -> music_agregator.v1.AlbumLabel - 25, // 21: music_agregator.v1.AlbumResult.external_ids:type_name -> music_agregator.v1.ExternalId - 34, // 22: music_agregator.v1.MonitorAlbumStreamRequest.start:type_name -> music_agregator.v1.StartMonitorRequest - 35, // 23: music_agregator.v1.MonitorAlbumStreamRequest.decision:type_name -> music_agregator.v1.UserDecision - 37, // 24: music_agregator.v1.MonitorAlbumStreamRequest.cancel:type_name -> music_agregator.v1.CancelRequest - 6, // 25: music_agregator.v1.StartMonitorRequest.indexer_options:type_name -> music_agregator.v1.IndexerOptions + 14, // 9: music_agregator.v1.AlbumDetail.downloads:type_name -> music_agregator.v1.DownloadInfo + 22, // 10: music_agregator.v1.AlbumDetail.release:type_name -> music_agregator.v1.AlbumReleaseDetail + 13, // 11: music_agregator.v1.AlbumInfo.album:type_name -> music_agregator.v1.AlbumDetail + 20, // 12: music_agregator.v1.AlbumInfo.tracks:type_name -> music_agregator.v1.TrackDetail + 16, // 13: music_agregator.v1.GetAlbumResponse.info:type_name -> music_agregator.v1.AlbumInfo + 16, // 14: music_agregator.v1.AnalyzeAlbumReleaseResponse.info:type_name -> music_agregator.v1.AlbumInfo + 21, // 15: music_agregator.v1.TrackDetail.artists:type_name -> music_agregator.v1.ArtistCredit + 26, // 16: music_agregator.v1.SearchArtistsResponse.artists:type_name -> music_agregator.v1.SearchArtistResult + 27, // 17: music_agregator.v1.SearchArtistResult.external_ids:type_name -> music_agregator.v1.ExternalId + 30, // 18: music_agregator.v1.GetArtistAlbumsResponse.albums:type_name -> music_agregator.v1.AlbumResult + 31, // 19: music_agregator.v1.AlbumResult.artists:type_name -> music_agregator.v1.AlbumArtistCredit + 32, // 20: music_agregator.v1.AlbumResult.label:type_name -> music_agregator.v1.AlbumLabel + 27, // 21: music_agregator.v1.AlbumResult.external_ids:type_name -> music_agregator.v1.ExternalId + 36, // 22: music_agregator.v1.MonitorAlbumStreamRequest.start:type_name -> music_agregator.v1.StartMonitorRequest + 37, // 23: music_agregator.v1.MonitorAlbumStreamRequest.decision:type_name -> music_agregator.v1.UserDecision + 39, // 24: music_agregator.v1.MonitorAlbumStreamRequest.cancel:type_name -> music_agregator.v1.CancelRequest + 8, // 25: music_agregator.v1.StartMonitorRequest.indexer_options:type_name -> music_agregator.v1.IndexerOptions 0, // 26: music_agregator.v1.StartMonitorRequest.quality:type_name -> music_agregator.v1.QualityType 2, // 27: music_agregator.v1.StartMonitorRequest.mode:type_name -> music_agregator.v1.InteractionMode - 36, // 28: music_agregator.v1.UserDecision.selected_ids:type_name -> music_agregator.v1.SelectedIds - 39, // 29: music_agregator.v1.MonitorAlbumStreamResponse.status:type_name -> music_agregator.v1.StatusUpdate - 40, // 30: music_agregator.v1.MonitorAlbumStreamResponse.prompt:type_name -> music_agregator.v1.PromptForDecision - 7, // 31: music_agregator.v1.MonitorAlbumStreamResponse.result:type_name -> music_agregator.v1.MonitorAlbumResponse - 41, // 32: music_agregator.v1.MonitorAlbumStreamResponse.error:type_name -> music_agregator.v1.ErrorUpdate + 38, // 28: music_agregator.v1.UserDecision.selected_ids:type_name -> music_agregator.v1.SelectedIds + 41, // 29: music_agregator.v1.MonitorAlbumStreamResponse.status:type_name -> music_agregator.v1.StatusUpdate + 42, // 30: music_agregator.v1.MonitorAlbumStreamResponse.prompt:type_name -> music_agregator.v1.PromptForDecision + 9, // 31: music_agregator.v1.MonitorAlbumStreamResponse.result:type_name -> music_agregator.v1.MonitorAlbumResponse + 43, // 32: music_agregator.v1.MonitorAlbumStreamResponse.error:type_name -> music_agregator.v1.ErrorUpdate 3, // 33: music_agregator.v1.StatusUpdate.step:type_name -> music_agregator.v1.MonitorStep - 42, // 34: music_agregator.v1.StatusUpdate.album_info:type_name -> music_agregator.v1.StreamAlbumInfo - 43, // 35: music_agregator.v1.StatusUpdate.torrents:type_name -> music_agregator.v1.TorrentList - 45, // 36: music_agregator.v1.StatusUpdate.release_info:type_name -> music_agregator.v1.ReleaseInfo + 44, // 34: music_agregator.v1.StatusUpdate.album_info:type_name -> music_agregator.v1.StreamAlbumInfo + 45, // 35: music_agregator.v1.StatusUpdate.torrents:type_name -> music_agregator.v1.TorrentList + 47, // 36: music_agregator.v1.StatusUpdate.release_info:type_name -> music_agregator.v1.ReleaseInfo 4, // 37: music_agregator.v1.PromptForDecision.type:type_name -> music_agregator.v1.PromptType - 46, // 38: music_agregator.v1.PromptForDecision.confirm:type_name -> music_agregator.v1.ConfirmPrompt - 47, // 39: music_agregator.v1.PromptForDecision.select_one:type_name -> music_agregator.v1.SelectOnePrompt - 48, // 40: music_agregator.v1.PromptForDecision.select_many:type_name -> music_agregator.v1.SelectManyPrompt + 48, // 38: music_agregator.v1.PromptForDecision.confirm:type_name -> music_agregator.v1.ConfirmPrompt + 49, // 39: music_agregator.v1.PromptForDecision.select_one:type_name -> music_agregator.v1.SelectOnePrompt + 50, // 40: music_agregator.v1.PromptForDecision.select_many:type_name -> music_agregator.v1.SelectManyPrompt 3, // 41: music_agregator.v1.ErrorUpdate.failed_step:type_name -> music_agregator.v1.MonitorStep - 44, // 42: music_agregator.v1.TorrentList.torrents:type_name -> music_agregator.v1.TorrentSummary - 49, // 43: music_agregator.v1.SelectOnePrompt.options:type_name -> music_agregator.v1.SelectOption - 49, // 44: music_agregator.v1.SelectManyPrompt.options:type_name -> music_agregator.v1.SelectOption - 5, // 45: music_agregator.v1.MusicAgregatorService.MonitorAlbum:input_type -> music_agregator.v1.MonitorAlbumRequest - 33, // 46: music_agregator.v1.MusicAgregatorService.MonitorAlbumStream:input_type -> music_agregator.v1.MonitorAlbumStreamRequest - 8, // 47: music_agregator.v1.MusicAgregatorService.GetArtists:input_type -> music_agregator.v1.GetArtistsRequest - 13, // 48: music_agregator.v1.MusicAgregatorService.GetAlbum:input_type -> music_agregator.v1.GetAlbumRequest - 16, // 49: music_agregator.v1.MusicAgregatorService.AnalyzeAlbumRelease:input_type -> music_agregator.v1.AnalyzeAlbumReleaseRequest - 22, // 50: music_agregator.v1.MusicAgregatorService.SearchArtists:input_type -> music_agregator.v1.SearchArtistsRequest - 26, // 51: music_agregator.v1.MusicAgregatorService.GetArtistAlbums:input_type -> music_agregator.v1.GetArtistAlbumsRequest - 31, // 52: music_agregator.v1.MusicAgregatorService.SubscribeEvents:input_type -> music_agregator.v1.SubscribeEventsRequest - 7, // 53: music_agregator.v1.MusicAgregatorService.MonitorAlbum:output_type -> music_agregator.v1.MonitorAlbumResponse - 38, // 54: music_agregator.v1.MusicAgregatorService.MonitorAlbumStream:output_type -> music_agregator.v1.MonitorAlbumStreamResponse - 9, // 55: music_agregator.v1.MusicAgregatorService.GetArtists:output_type -> music_agregator.v1.GetArtistsResponse - 15, // 56: music_agregator.v1.MusicAgregatorService.GetAlbum:output_type -> music_agregator.v1.GetAlbumResponse - 17, // 57: music_agregator.v1.MusicAgregatorService.AnalyzeAlbumRelease:output_type -> music_agregator.v1.AnalyzeAlbumReleaseResponse - 23, // 58: music_agregator.v1.MusicAgregatorService.SearchArtists:output_type -> music_agregator.v1.SearchArtistsResponse - 27, // 59: music_agregator.v1.MusicAgregatorService.GetArtistAlbums:output_type -> music_agregator.v1.GetArtistAlbumsResponse - 32, // 60: music_agregator.v1.MusicAgregatorService.SubscribeEvents:output_type -> music_agregator.v1.AlbumEvent - 53, // [53:61] is the sub-list for method output_type - 45, // [45:53] is the sub-list for method input_type + 46, // 42: music_agregator.v1.TorrentList.torrents:type_name -> music_agregator.v1.TorrentSummary + 51, // 43: music_agregator.v1.SelectOnePrompt.options:type_name -> music_agregator.v1.SelectOption + 51, // 44: music_agregator.v1.SelectManyPrompt.options:type_name -> music_agregator.v1.SelectOption + 7, // 45: music_agregator.v1.MusicAgregatorService.MonitorAlbum:input_type -> music_agregator.v1.MonitorAlbumRequest + 35, // 46: music_agregator.v1.MusicAgregatorService.MonitorAlbumStream:input_type -> music_agregator.v1.MonitorAlbumStreamRequest + 10, // 47: music_agregator.v1.MusicAgregatorService.GetArtists:input_type -> music_agregator.v1.GetArtistsRequest + 15, // 48: music_agregator.v1.MusicAgregatorService.GetAlbum:input_type -> music_agregator.v1.GetAlbumRequest + 18, // 49: music_agregator.v1.MusicAgregatorService.AnalyzeAlbumRelease:input_type -> music_agregator.v1.AnalyzeAlbumReleaseRequest + 24, // 50: music_agregator.v1.MusicAgregatorService.SearchArtists:input_type -> music_agregator.v1.SearchArtistsRequest + 28, // 51: music_agregator.v1.MusicAgregatorService.GetArtistAlbums:input_type -> music_agregator.v1.GetArtistAlbumsRequest + 33, // 52: music_agregator.v1.MusicAgregatorService.SubscribeEvents:input_type -> music_agregator.v1.SubscribeEventsRequest + 5, // 53: music_agregator.v1.MusicAgregatorService.ResyncAlbum:input_type -> music_agregator.v1.ResyncAlbumRequest + 9, // 54: music_agregator.v1.MusicAgregatorService.MonitorAlbum:output_type -> music_agregator.v1.MonitorAlbumResponse + 40, // 55: music_agregator.v1.MusicAgregatorService.MonitorAlbumStream:output_type -> music_agregator.v1.MonitorAlbumStreamResponse + 11, // 56: music_agregator.v1.MusicAgregatorService.GetArtists:output_type -> music_agregator.v1.GetArtistsResponse + 17, // 57: music_agregator.v1.MusicAgregatorService.GetAlbum:output_type -> music_agregator.v1.GetAlbumResponse + 19, // 58: music_agregator.v1.MusicAgregatorService.AnalyzeAlbumRelease:output_type -> music_agregator.v1.AnalyzeAlbumReleaseResponse + 25, // 59: music_agregator.v1.MusicAgregatorService.SearchArtists:output_type -> music_agregator.v1.SearchArtistsResponse + 29, // 60: music_agregator.v1.MusicAgregatorService.GetArtistAlbums:output_type -> music_agregator.v1.GetArtistAlbumsResponse + 34, // 61: music_agregator.v1.MusicAgregatorService.SubscribeEvents:output_type -> music_agregator.v1.AlbumEvent + 6, // 62: music_agregator.v1.MusicAgregatorService.ResyncAlbum:output_type -> music_agregator.v1.ResyncAlbumResponse + 54, // [54:63] is the sub-list for method output_type + 45, // [45:54] is the sub-list for method input_type 45, // [45:45] is the sub-list for extension type_name 45, // [45:45] is the sub-list for extension extendee 0, // [0:45] is the sub-list for field type_name @@ -4202,28 +4317,28 @@ func file_music_agregator_v1_music_agregator_proto_init() { if File_music_agregator_v1_music_agregator_proto != nil { return } - file_music_agregator_v1_music_agregator_proto_msgTypes[28].OneofWrappers = []any{ + file_music_agregator_v1_music_agregator_proto_msgTypes[30].OneofWrappers = []any{ (*MonitorAlbumStreamRequest_Start)(nil), (*MonitorAlbumStreamRequest_Decision)(nil), (*MonitorAlbumStreamRequest_Cancel)(nil), } - file_music_agregator_v1_music_agregator_proto_msgTypes[30].OneofWrappers = []any{ + file_music_agregator_v1_music_agregator_proto_msgTypes[32].OneofWrappers = []any{ (*UserDecision_Confirm)(nil), (*UserDecision_SelectedId)(nil), (*UserDecision_SelectedIds)(nil), } - file_music_agregator_v1_music_agregator_proto_msgTypes[33].OneofWrappers = []any{ + file_music_agregator_v1_music_agregator_proto_msgTypes[35].OneofWrappers = []any{ (*MonitorAlbumStreamResponse_Status)(nil), (*MonitorAlbumStreamResponse_Prompt)(nil), (*MonitorAlbumStreamResponse_Result)(nil), (*MonitorAlbumStreamResponse_Error)(nil), } - file_music_agregator_v1_music_agregator_proto_msgTypes[34].OneofWrappers = []any{ + file_music_agregator_v1_music_agregator_proto_msgTypes[36].OneofWrappers = []any{ (*StatusUpdate_AlbumInfo)(nil), (*StatusUpdate_Torrents)(nil), (*StatusUpdate_ReleaseInfo)(nil), } - file_music_agregator_v1_music_agregator_proto_msgTypes[35].OneofWrappers = []any{ + file_music_agregator_v1_music_agregator_proto_msgTypes[37].OneofWrappers = []any{ (*PromptForDecision_Confirm)(nil), (*PromptForDecision_SelectOne)(nil), (*PromptForDecision_SelectMany)(nil), @@ -4234,7 +4349,7 @@ func file_music_agregator_v1_music_agregator_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_music_agregator_v1_music_agregator_proto_rawDesc), len(file_music_agregator_v1_music_agregator_proto_rawDesc)), NumEnums: 5, - NumMessages: 45, + NumMessages: 47, NumExtensions: 0, NumServices: 1, }, diff --git a/gen/music_agregator/v1/music_agregator_grpc.pb.go b/gen/music_agregator/v1/music_agregator_grpc.pb.go index 0e0d085..54e6347 100644 --- a/gen/music_agregator/v1/music_agregator_grpc.pb.go +++ b/gen/music_agregator/v1/music_agregator_grpc.pb.go @@ -27,6 +27,7 @@ const ( MusicAgregatorService_SearchArtists_FullMethodName = "/music_agregator.v1.MusicAgregatorService/SearchArtists" MusicAgregatorService_GetArtistAlbums_FullMethodName = "/music_agregator.v1.MusicAgregatorService/GetArtistAlbums" MusicAgregatorService_SubscribeEvents_FullMethodName = "/music_agregator.v1.MusicAgregatorService/SubscribeEvents" + MusicAgregatorService_ResyncAlbum_FullMethodName = "/music_agregator.v1.MusicAgregatorService/ResyncAlbum" ) // MusicAgregatorServiceClient is the client API for MusicAgregatorService service. @@ -42,6 +43,7 @@ type MusicAgregatorServiceClient interface { SearchArtists(ctx context.Context, in *SearchArtistsRequest, opts ...grpc.CallOption) (*SearchArtistsResponse, error) GetArtistAlbums(ctx context.Context, in *GetArtistAlbumsRequest, opts ...grpc.CallOption) (*GetArtistAlbumsResponse, error) SubscribeEvents(ctx context.Context, in *SubscribeEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[AlbumEvent], error) + ResyncAlbum(ctx context.Context, in *ResyncAlbumRequest, opts ...grpc.CallOption) (*ResyncAlbumResponse, error) } type musicAgregatorServiceClient struct { @@ -145,6 +147,16 @@ func (c *musicAgregatorServiceClient) SubscribeEvents(ctx context.Context, in *S // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type MusicAgregatorService_SubscribeEventsClient = grpc.ServerStreamingClient[AlbumEvent] +func (c *musicAgregatorServiceClient) ResyncAlbum(ctx context.Context, in *ResyncAlbumRequest, opts ...grpc.CallOption) (*ResyncAlbumResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ResyncAlbumResponse) + err := c.cc.Invoke(ctx, MusicAgregatorService_ResyncAlbum_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // MusicAgregatorServiceServer is the server API for MusicAgregatorService service. // All implementations must embed UnimplementedMusicAgregatorServiceServer // for forward compatibility. @@ -158,6 +170,7 @@ type MusicAgregatorServiceServer interface { SearchArtists(context.Context, *SearchArtistsRequest) (*SearchArtistsResponse, error) GetArtistAlbums(context.Context, *GetArtistAlbumsRequest) (*GetArtistAlbumsResponse, error) SubscribeEvents(*SubscribeEventsRequest, grpc.ServerStreamingServer[AlbumEvent]) error + ResyncAlbum(context.Context, *ResyncAlbumRequest) (*ResyncAlbumResponse, error) mustEmbedUnimplementedMusicAgregatorServiceServer() } @@ -192,6 +205,9 @@ func (UnimplementedMusicAgregatorServiceServer) GetArtistAlbums(context.Context, func (UnimplementedMusicAgregatorServiceServer) SubscribeEvents(*SubscribeEventsRequest, grpc.ServerStreamingServer[AlbumEvent]) error { return status.Error(codes.Unimplemented, "method SubscribeEvents not implemented") } +func (UnimplementedMusicAgregatorServiceServer) ResyncAlbum(context.Context, *ResyncAlbumRequest) (*ResyncAlbumResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ResyncAlbum not implemented") +} func (UnimplementedMusicAgregatorServiceServer) mustEmbedUnimplementedMusicAgregatorServiceServer() {} func (UnimplementedMusicAgregatorServiceServer) testEmbeddedByValue() {} @@ -339,6 +355,24 @@ func _MusicAgregatorService_SubscribeEvents_Handler(srv interface{}, stream grpc // This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. type MusicAgregatorService_SubscribeEventsServer = grpc.ServerStreamingServer[AlbumEvent] +func _MusicAgregatorService_ResyncAlbum_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ResyncAlbumRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MusicAgregatorServiceServer).ResyncAlbum(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: MusicAgregatorService_ResyncAlbum_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MusicAgregatorServiceServer).ResyncAlbum(ctx, req.(*ResyncAlbumRequest)) + } + return interceptor(ctx, in, info, handler) +} + // MusicAgregatorService_ServiceDesc is the grpc.ServiceDesc for MusicAgregatorService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -370,6 +404,10 @@ var MusicAgregatorService_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetArtistAlbums", Handler: _MusicAgregatorService_GetArtistAlbums_Handler, }, + { + MethodName: "ResyncAlbum", + Handler: _MusicAgregatorService_ResyncAlbum_Handler, + }, }, Streams: []grpc.StreamDesc{ { diff --git a/internal/database/download_repository.go b/internal/database/download_repository.go index 39c7d98..e439e2b 100644 --- a/internal/database/download_repository.go +++ b/internal/database/download_repository.go @@ -173,6 +173,19 @@ func (r *DownloadRepository) GetByID(ctx context.Context, id string) (*Download, return d, nil } +func (r *DownloadRepository) GetLatestCompleted(ctx context.Context, albumID string) (*Download, error) { + d := &Download{} + err := r.pool.QueryRow(ctx, + `SELECT id, torrent_id, album_id, format, quality, state, qbit_hash, save_path, error_message, queued_at, started_at, completed_at, created_at, updated_at + FROM downloads WHERE album_id = $1 AND state = 'completed' + ORDER BY completed_at DESC LIMIT 1`, albumID, + ).Scan(&d.ID, &d.TorrentID, &d.AlbumID, &d.Format, &d.Quality, &d.State, &d.QbitHash, &d.SavePath, &d.ErrorMessage, &d.QueuedAt, &d.StartedAt, &d.CompletedAt, &d.CreatedAt, &d.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("getting latest completed download: %w", err) + } + return d, nil +} + func (r *DownloadRepository) GetByAlbumIDs(ctx context.Context, albumIDs []string) (map[string][]*Download, error) { if len(albumIDs) == 0 { return nil, nil diff --git a/internal/monitor_workflow.go b/internal/monitor_workflow.go index 47a6b89..3b648a7 100644 --- a/internal/monitor_workflow.go +++ b/internal/monitor_workflow.go @@ -222,7 +222,10 @@ func (w *monitorWorkflow) run(ctx context.Context) error { return err } - parsed := w.service.parseSearchResults(searchResult, album) + parsed := w.service.parseSearchResults(ctx, searchResult, album, func(phase string, current, total int) { + w.publisher.PublishStatus(ctx, pb.MonitorStep_MONITOR_STEP_PARSING_RESULTS, + fmt.Sprintf("%s: %d/%d", phase, current, total), nil) + }) if len(parsed) > 0 { summaries := make([]*pb.TorrentSummary, len(parsed)) @@ -250,6 +253,13 @@ func (w *monitorWorkflow) run(ctx context.Context) error { return err } + parsed = filterByAlbumMatch(parsed, album.GetTitle(), artistName) + if len(parsed) == 0 { + err := fmt.Errorf("no torrents match album title %q", album.GetTitle()) + w.publisher.PublishError(ctx, pb.MonitorStep_MONITOR_STEP_PARSING_RESULTS, err, false) + return err + } + if w.mode == pb.InteractionMode_INTERACTION_MODE_MANUAL && len(parsed) > 1 { options := make([]*pb.SelectOption, len(parsed)) defaultIDs := make([]string, len(parsed)) @@ -366,7 +376,7 @@ func (w *monitorWorkflow) run(ctx context.Context) error { } best = filtered[selectedIdx] } else { - best = selectBestRelease(filtered) + best = selectBestRelease(filtered, album.GetTitle()) } w.publisher.PublishStatus(ctx, pb.MonitorStep_MONITOR_STEP_SELECTING_RELEASE, diff --git a/internal/server.go b/internal/server.go index 55906b4..a64639b 100644 --- a/internal/server.go +++ b/internal/server.go @@ -16,6 +16,7 @@ import ( "homelab.lan/music-agregator/internal/config" "homelab.lan/music-agregator/internal/database" "homelab.lan/music-agregator/internal/eventbus" + "homelab.lan/music-agregator/internal/musicfs" "homelab.lan/music-agregator/internal/torrent" ) @@ -26,8 +27,8 @@ type MusicAgregatorServer struct { pb.UnimplementedMusicAgregatorServiceServer } -func NewMusicAgregatorServer(cfg config.Config, riverClient *river.Client[pgx.Tx], torrentClient torrent.TorrentClient, pathMapper *torrent.PathMapper, db *database.DB, bus *eventbus.EventBus) (*MusicAgregatorServer, error) { - service, err := NewMusicAgregatorService(cfg, riverClient, torrentClient, pathMapper, db) +func NewMusicAgregatorServer(cfg config.Config, riverClient *river.Client[pgx.Tx], torrentClient torrent.TorrentClient, pathMapper *torrent.PathMapper, db *database.DB, bus *eventbus.EventBus, musicfsClient *musicfs.Client) (*MusicAgregatorServer, error) { + service, err := NewMusicAgregatorService(cfg, riverClient, torrentClient, pathMapper, db, musicfsClient) if err != nil { log.Err(err).Msg("failed to create MusicAgregatorService") return nil, err @@ -245,6 +246,10 @@ func (s *MusicAgregatorServer) GetArtistAlbums(ctx context.Context, req *pb.GetA return s.service.GetArtistAlbums(ctx, req) } +func (s *MusicAgregatorServer) ResyncAlbum(ctx context.Context, req *pb.ResyncAlbumRequest) (*pb.ResyncAlbumResponse, error) { + return s.service.ResyncAlbum(ctx, req.GetAlbumId()) +} + func (s *MusicAgregatorServer) Register(server *grpc.Server) { pb.RegisterMusicAgregatorServiceServer(server, s) } diff --git a/internal/service.go b/internal/service.go index 055046c..969c5b4 100644 --- a/internal/service.go +++ b/internal/service.go @@ -5,8 +5,11 @@ import ( "fmt" "io" "net/http" + "regexp" + "sort" "strings" "sync" + "sync/atomic" "time" "github.com/jackc/pgx/v5" @@ -23,7 +26,9 @@ import ( "homelab.lan/music-agregator/internal/config" "homelab.lan/music-agregator/internal/database" "homelab.lan/music-agregator/internal/indexer" + albumMatcher "homelab.lan/music-agregator/internal/matcher" "homelab.lan/music-agregator/internal/metadata" + "homelab.lan/music-agregator/internal/musicfs" "homelab.lan/music-agregator/internal/release" "homelab.lan/music-agregator/internal/torrent" torrentParser "homelab.lan/music-agregator/internal/tracker" @@ -54,11 +59,12 @@ type MusicAgregatorService struct { analyzer *analysis.ReleaseAnalyzer workflowRuns *database.WorkflowRunRepository albumEvents *database.AlbumEventRepository + musicfsClient *musicfs.Client shutdownCtx context.Context shutdownCancel context.CancelFunc } -func NewMusicAgregatorService(cfg config.Config, riverClient *river.Client[pgx.Tx], torrentClient torrent.TorrentClient, pathMapper *torrent.PathMapper, db *database.DB) (*MusicAgregatorService, error) { +func NewMusicAgregatorService(cfg config.Config, riverClient *river.Client[pgx.Tx], torrentClient torrent.TorrentClient, pathMapper *torrent.PathMapper, db *database.DB, musicfsClient *musicfs.Client) (*MusicAgregatorService, error) { idx, err := indexer.NewIndexerService(cfg, riverClient, nil) if err != nil { log.Err(err).Msg("failed to create IndexerService") @@ -96,6 +102,7 @@ func NewMusicAgregatorService(cfg config.Config, riverClient *river.Client[pgx.T analyzer: analysis.NewReleaseAnalyzer(db), workflowRuns: database.NewWorkflowRunRepository(db.Pool), albumEvents: database.NewAlbumEventRepository(db.Pool), + musicfsClient: musicfsClient, shutdownCtx: ctx, shutdownCancel: cancel, }, nil @@ -560,12 +567,21 @@ func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb. return nil, err } - parsed := service.parseSearchResults(searchResult, album) + parsed := service.parseSearchResults(ctx, searchResult, album, nil) if len(parsed) == 0 { return nil, status.Errorf(codes.NotFound, "no torrents found for %s", album.GetTitle()) } + albumArtist := "" + if len(album.GetArtists()) > 0 { + albumArtist = album.GetArtists()[0].GetArtist().GetName() + } + parsed = filterByAlbumMatch(parsed, album.GetTitle(), albumArtist) + if len(parsed) == 0 { + return nil, status.Errorf(codes.NotFound, "no torrents match album title %q", album.GetTitle()) + } + filtered := filterByQuality(parsed, req.GetQuality()) if len(filtered) == 0 { return nil, status.Errorf(codes.NotFound, "no releases match quality filter for %s", album.GetTitle()) @@ -576,7 +592,7 @@ func (service *MusicAgregatorService) MonitorAlbum(ctx context.Context, req *pb. return nil, status.Errorf(codes.NotFound, "no releases with active seeders for %s", album.GetTitle()) } - best := selectBestRelease(filtered) + best := selectBestRelease(filtered, album.GetTitle()) if err := service.addToTorrentClient(best); err != nil { return nil, err @@ -630,64 +646,237 @@ func (service *MusicAgregatorService) searchIndexer(album *metadataPb.Album, tra } func buildSearchQueries(artist, title string) []string { - base := title - if artist != "" { - base = artist + " " + title + artist = normalizeSearchQuery(artist) + title = normalizeSearchQuery(title) + + clean := cleanAlbumTitle(title) + + var queries []string + seen := make(map[string]bool) + add := func(q string) { + q = strings.TrimSpace(q) + if q != "" && !seen[strings.ToLower(q)] { + seen[strings.ToLower(q)] = true + queries = append(queries, q) + } } - queries := []string{base} - - stripped := stripParenthetical(title) - if stripped != title { - q := stripped + withArtist := func(t string) string { if artist != "" { - q = artist + " " + stripped + return artist + " " + t } - queries = append(queries, q) + return t + } + + add(withArtist(clean)) + + noPunct := stripPunctuation(clean) + add(withArtist(noPunct)) + + if artist != "" { + add(artist) } return queries } -func stripParenthetical(s string) string { - idx := strings.Index(s, "(") - if idx > 0 { - return strings.TrimSpace(s[:idx]) +var unicodeReplacer = strings.NewReplacer( + "\u2019", "'", // right single quote + "\u2018", "'", // left single quote + "\u201C", "\"", // left double quote + "\u201D", "\"", // right double quote + "\u2013", "-", // en dash + "\u2014", "-", // em dash + "\u2026", "...", // ellipsis +) + +func normalizeSearchQuery(s string) string { + s = unicodeReplacer.Replace(s) + for strings.Contains(s, " ") { + s = strings.ReplaceAll(s, " ", " ") } - return s + return strings.TrimSpace(s) } -func (service *MusicAgregatorService) parseSearchResults(searchResult *indexer.SearchResponse, album *metadataPb.Album) []parsedItem { - parser := torrentParser.NewGenericParser() - var parsed []parsedItem +var editionTagPattern = regexp.MustCompile(`(?i)\b(remaster(?:ed)?|deluxe(?:\s+edition)?|expanded(?:\s+edition)?|anniversary(?:\s+edition)?|special\s+edition|bonus\s+track|limited\s+edition|collector'?s?\s+edition|super\s+deluxe|standard\s+edition)\b`) +var bracketPattern = regexp.MustCompile(`[\(\[\{][^)\]\}]*[\)\]\}]`) - for _, item := range searchResult.Items { +func cleanAlbumTitle(title string) string { + clean := bracketPattern.ReplaceAllString(title, "") + clean = editionTagPattern.ReplaceAllString(clean, "") + clean = strings.TrimRight(clean, " -–—:") + for strings.Contains(clean, " ") { + clean = strings.ReplaceAll(clean, " ", " ") + } + clean = strings.TrimSpace(clean) + if clean == "" { + return title + } + return clean +} + +func extractEditionTags(title string) []string { + matches := editionTagPattern.FindAllString(title, -1) + tags := make([]string, len(matches)) + for i, m := range matches { + tags[i] = strings.ToLower(strings.TrimSpace(m)) + } + return tags +} + +func stripPunctuation(s string) string { + var b strings.Builder + for _, r := range s { + switch { + case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9', r == ' ': + b.WriteRune(r) + default: + b.WriteRune(' ') + } + } + result := b.String() + for strings.Contains(result, " ") { + result = strings.ReplaceAll(result, " ", " ") + } + return strings.TrimSpace(result) +} + +type resolveProgressFunc func(phase string, current, total int) + +const maxMagnetResolves = 5 + +func (service *MusicAgregatorService) parseSearchResults(ctx context.Context, searchResult *indexer.SearchResponse, album *metadataPb.Album, onProgress resolveProgressFunc) []parsedItem { + var candidates []*indexer.SearchItemResult + for i := range searchResult.Items { + item := searchResult.Items[i] if item.DownloadLink == "" { log.Trace().Str("title", item.Title).Msg("skipping item without download link") continue } - if item.Seeders == 0 { log.Warn().Str("title", item.Title).Str("tracker", item.Tracker).Msg("skipping torrent with no seeders") continue } - - out := service.resolveRelease(parser, item, album) - - log.Debug(). - Str("title", item.Title). - Str("format", out.rel.Format.String()). - Int("tracks", out.rel.TrackCount). - Bool("lossless", out.rel.Format.IsLossless()). - Int("seeders", item.Seeders). - Int("real_seeders", out.realSeeders). - Str("tracker", item.Tracker). - Msg("release parsed") - - parsed = append(parsed, parsedItem{item: item, rel: out.rel, torrentData: out.torrentData, realSeeders: out.realSeeders}) + candidates = append(candidates, item) } - log.Debug().Int("total", len(searchResult.Items)).Int("parsed", len(parsed)).Msg("parsing complete") + total := len(candidates) + if total == 0 { + return nil + } + + progress := func(phase string, current, t int) { + if onProgress != nil { + onProgress(phase, current, t) + } + } + + progress("Pre-parsing titles", 0, total) + parser := torrentParser.NewGenericParser() + parsed := make([]parsedItem, total) + for i, item := range candidates { + rel := parser.Parse(item.Title) + parsed[i] = parsedItem{ + item: item, + rel: rel, + realSeeders: -1, + } + } + log.Info().Int("candidates", total).Msg("phase 1: title pre-parse complete") + progress("Pre-parsed titles", total, total) + + progress("Checking cache", 0, total) + var cacheHits int + for i := range parsed { + p := &parsed[i] + infoHash := torrentParser.ExtractInfoHash(p.item.DownloadLink) + if infoHash == "" { + if h, ok := p.item.Attrs["infohash"]; ok { + infoHash = strings.ToLower(h) + } + } + if infoHash == "" { + continue + } + + cached, err := service.torrents.GetByInfoHash(ctx, infoHash) + if err != nil || len(cached.TorrentFile) == 0 { + continue + } + + fullParser := torrentParser.NewGenericParser() + p.rel = fullParser.ParseTorrent(cached.TorrentFile, album) + p.torrentData = cached.TorrentFile + cacheHits++ + + log.Debug(). + Str("title", p.item.Title). + Str("hash", infoHash). + Str("format", p.rel.Format.String()). + Msg("cache hit") + } + log.Info().Int("cache_hits", cacheHits).Int("candidates", total).Msg("phase 2: cache lookup complete") + progress("Cache hits", cacheHits, total) + + var needsResolve []int + for i := range parsed { + if parsed[i].torrentData == nil { + needsResolve = append(needsResolve, i) + } + } + + sort.Slice(needsResolve, func(a, b int) bool { + return parsed[needsResolve[a]].item.Seeders > parsed[needsResolve[b]].item.Seeders + }) + if len(needsResolve) > maxMagnetResolves { + needsResolve = needsResolve[:maxMagnetResolves] + } + + resolveCount := len(needsResolve) + if resolveCount > 0 { + log.Info().Int("to_resolve", resolveCount).Int("skipped", total-cacheHits-resolveCount).Msg("phase 3: resolving top candidates") + progress("Resolving torrents", 0, resolveCount) + + const maxWorkers = 10 + sem := make(chan struct{}, maxWorkers) + var wg sync.WaitGroup + var resolved atomic.Int32 + + for _, idx := range needsResolve { + wg.Add(1) + go func(i int) { + defer wg.Done() + sem <- struct{}{} + defer func() { <-sem }() + + p := &parsed[i] + resolveParser := torrentParser.NewGenericParser() + out := service.resolveRelease(resolveParser, p.item, album) + p.rel = out.rel + p.torrentData = out.torrentData + p.realSeeders = out.realSeeders + + n := int(resolved.Add(1)) + progress("Resolving torrents", n, resolveCount) + + log.Debug(). + Str("title", p.item.Title). + Str("format", out.rel.Format.String()). + Int("real_seeders", out.realSeeders). + Msg("resolved") + }(idx) + } + + wg.Wait() + } + + log.Debug(). + Int("total", total). + Int("cache_hits", cacheHits). + Int("resolved", resolveCount). + Int("title_only", total-cacheHits-resolveCount). + Msg("parsing complete") + return parsed } @@ -729,6 +918,26 @@ func (service *MusicAgregatorService) resolveRelease(parser *torrentParser.Gener } } +func filterByAlbumMatch(items []parsedItem, albumTitle, artistName string) []parsedItem { + var matched []parsedItem + for _, p := range items { + score := albumMatcher.AlbumMatchScore(albumTitle, p.item.Title, artistName) + if score >= albumMatcher.MatchThreshold { + matched = append(matched, p) + } else { + log.Debug(). + Str("title", p.item.Title). + Float64("score", score). + Str("wanted", albumTitle). + Msg("filtered out by album match") + } + } + if len(matched) == 0 { + log.Warn().Str("album", albumTitle).Int("total", len(items)).Msg("no torrents match album title") + } + return matched +} + func filterByQuality(items []parsedItem, quality pb.QualityType) []parsedItem { var filtered []parsedItem for _, p := range items { @@ -767,10 +976,12 @@ func filterByActiveSeeders(items []parsedItem) []parsedItem { return withSeeders } -func selectBestRelease(items []parsedItem) parsedItem { +func selectBestRelease(items []parsedItem, albumTitle string) parsedItem { + editionTags := extractEditionTags(albumTitle) + best := items[0] for _, p := range items[1:] { - if betterRelease(p, best) { + if betterRelease(p, best, editionTags) { best = p } } @@ -782,12 +993,19 @@ func selectBestRelease(items []parsedItem) parsedItem { Int("real_seeders", best.realSeeders). Str("tracker", best.item.Tracker). Str("hash", best.rel.InfoHash). + Strs("edition_tags", editionTags). Msg("best release selected") return best } -func betterRelease(candidate, current parsedItem) bool { +func betterRelease(candidate, current parsedItem, editionTags []string) bool { + cEdition := editionMatchScore(candidate.item.Title, editionTags) + bEdition := editionMatchScore(current.item.Title, editionTags) + if cEdition != bEdition { + return cEdition > bEdition + } + cHasReal := candidate.realSeeders > 0 bHasReal := current.realSeeders > 0 @@ -803,6 +1021,20 @@ func betterRelease(candidate, current parsedItem) bool { return candidate.item.Seeders > current.item.Seeders } +func editionMatchScore(torrentTitle string, editionTags []string) int { + if len(editionTags) == 0 { + return 0 + } + lower := strings.ToLower(torrentTitle) + score := 0 + for _, tag := range editionTags { + if strings.Contains(lower, tag) { + score++ + } + } + return score +} + func (service *MusicAgregatorService) addToTorrentClient(best parsedItem) error { if best.rel.InfoHash != "" { existing, err := service.torrentClient.Find(torrent.FindOptions{Hash: best.rel.InfoHash}) @@ -1054,6 +1286,70 @@ func downloadTorrentData(url string) ([]byte, error) { return data, nil } +func (service *MusicAgregatorService) ResyncAlbum(ctx context.Context, albumID string) (*pb.ResyncAlbumResponse, error) { + if service.musicfsClient == nil { + return nil, status.Error(codes.FailedPrecondition, "musicfs not configured") + } + + download, err := service.downloads.GetLatestCompleted(ctx, albumID) + if err != nil { + return nil, status.Errorf(codes.NotFound, "no completed download for album %s: %v", albumID, err) + } + + subdir := "" + if download.QbitHash != "" { + results, err := service.torrentClient.Find(torrent.FindOptions{Hash: download.QbitHash}) + if err == nil && len(results) > 0 { + contentPath := results[0].ContentPath + if service.pathMapper != nil { + contentPath = service.pathMapper.ToHost(contentPath) + } + subdir = musicfs.DeriveSubdir(service.config.MusicFS.OriginRoot, contentPath) + } + } + + log.Info(). + Str("album_id", albumID). + Str("subdir", subdir). + Msg("resyncing album with musicfs") + + result, err := service.musicfsClient.TriggerRescan(ctx, service.config.MusicFS.OriginID, subdir) + if err != nil { + return nil, status.Errorf(codes.Internal, "musicfs rescan failed: %v", err) + } + + log.Info(). + Int("new_files", len(result.NewFiles)). + Uint64("bytes_synced", result.BytesSynced). + Msg("musicfs rescan complete") + + var filesEnriched int + if len(result.NewFiles) > 0 { + dbAlbum, err := service.metadata.GetAlbumByID(ctx, albumID) + if err != nil { + log.Warn().Err(err).Str("album_id", albumID).Msg("failed to get album for enrichment") + } else { + albumMeta, err := service.metadata.GetAlbum(ctx, dbAlbum.ExternalID) + if err != nil { + log.Warn().Err(err).Str("external_id", dbAlbum.ExternalID).Msg("failed to get album metadata for enrichment") + } else { + err = service.musicfsClient.EnrichFiles(ctx, result.NewFiles, albumMeta) + if err != nil { + log.Warn().Err(err).Msg("musicfs enrichment failed") + } else { + filesEnriched = len(result.NewFiles) + } + } + } + } + + return &pb.ResyncAlbumResponse{ + FilesSynced: int32(len(result.NewFiles)), + FilesEnriched: int32(filesEnriched), + BytesSynced: result.BytesSynced, + }, nil +} + func (service *MusicAgregatorService) SearchArtists(ctx context.Context, req *pb.SearchArtistsRequest) (*pb.SearchArtistsResponse, error) { resp, err := service.metadata.SearchArtists(ctx, req.GetQuery(), req.GetLimit(), req.GetOffset()) if err != nil { diff --git a/internal/tracker/magnet.go b/internal/tracker/magnet.go index 1302476..8c4708a 100644 --- a/internal/tracker/magnet.go +++ b/internal/tracker/magnet.go @@ -3,6 +3,8 @@ package tracker import ( "context" "fmt" + "net/url" + "strings" "time" "github.com/anacrolix/torrent" @@ -11,6 +13,18 @@ import ( "github.com/rs/zerolog/log" ) +func ExtractInfoHash(magnetURI string) string { + u, err := url.Parse(magnetURI) + if err != nil { + return "" + } + xt := u.Query().Get("xt") + if strings.HasPrefix(xt, "urn:btih:") { + return strings.ToLower(xt[len("urn:btih:"):]) + } + return "" +} + type ResolveResult struct { Data []byte ConnectedSeeders int diff --git a/proto/music_agregator/v1/music_agregator.proto b/proto/music_agregator/v1/music_agregator.proto index 5bb9127..598f114 100644 --- a/proto/music_agregator/v1/music_agregator.proto +++ b/proto/music_agregator/v1/music_agregator.proto @@ -13,6 +13,17 @@ service MusicAgregatorService { rpc SearchArtists(SearchArtistsRequest) returns (SearchArtistsResponse) {} rpc GetArtistAlbums(GetArtistAlbumsRequest) returns (GetArtistAlbumsResponse) {} rpc SubscribeEvents(SubscribeEventsRequest) returns (stream AlbumEvent) {} + rpc ResyncAlbum(ResyncAlbumRequest) returns (ResyncAlbumResponse) {} +} + +message ResyncAlbumRequest { + string album_id = 1; +} + +message ResyncAlbumResponse { + int32 files_synced = 1; + int32 files_enriched = 2; + uint64 bytes_synced = 3; } message MonitorAlbumRequest {