Some more

This commit is contained in:
Alexander
2026-07-01 20:07:49 +02:00
parent b448e076bc
commit d52ce9508e
4 changed files with 4279 additions and 0 deletions
+3274
View File
File diff suppressed because it is too large Load Diff
+775
View File
@@ -0,0 +1,775 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.1
// - protoc (unknown)
// source: musicfs.proto
package musicfsv1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
MusicFS_Search_FullMethodName = "/musicfs.v1.MusicFS/Search"
MusicFS_SearchStream_FullMethodName = "/musicfs.v1.MusicFS/SearchStream"
MusicFS_GetStatus_FullMethodName = "/musicfs.v1.MusicFS/GetStatus"
MusicFS_Shutdown_FullMethodName = "/musicfs.v1.MusicFS/Shutdown"
MusicFS_GetCacheStats_FullMethodName = "/musicfs.v1.MusicFS/GetCacheStats"
MusicFS_ClearCache_FullMethodName = "/musicfs.v1.MusicFS/ClearCache"
MusicFS_Prefetch_FullMethodName = "/musicfs.v1.MusicFS/Prefetch"
MusicFS_ListOrigins_FullMethodName = "/musicfs.v1.MusicFS/ListOrigins"
MusicFS_GetOriginHealth_FullMethodName = "/musicfs.v1.MusicFS/GetOriginHealth"
MusicFS_RescanOrigin_FullMethodName = "/musicfs.v1.MusicFS/RescanOrigin"
MusicFS_SubscribeEvents_FullMethodName = "/musicfs.v1.MusicFS/SubscribeEvents"
)
// MusicFSClient is the client API for MusicFS service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type MusicFSClient interface {
Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*SearchResponse, error)
SearchStream(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SearchResult], error)
GetStatus(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StatusResponse, error)
Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*Empty, error)
GetCacheStats(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*CacheStats, error)
ClearCache(ctx context.Context, in *ClearCacheRequest, opts ...grpc.CallOption) (*ClearCacheResponse, error)
Prefetch(ctx context.Context, in *PrefetchRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[PrefetchProgress], error)
ListOrigins(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*OriginsResponse, error)
GetOriginHealth(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (*OriginHealthResponse, error)
RescanOrigin(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SyncProgress], error)
SubscribeEvents(ctx context.Context, in *EventFilter, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Event], error)
}
type musicFSClient struct {
cc grpc.ClientConnInterface
}
func NewMusicFSClient(cc grpc.ClientConnInterface) MusicFSClient {
return &musicFSClient{cc}
}
func (c *musicFSClient) Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*SearchResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SearchResponse)
err := c.cc.Invoke(ctx, MusicFS_Search_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) SearchStream(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SearchResult], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &MusicFS_ServiceDesc.Streams[0], MusicFS_SearchStream_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[SearchRequest, SearchResult]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_SearchStreamClient = grpc.ServerStreamingClient[SearchResult]
func (c *musicFSClient) GetStatus(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StatusResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(StatusResponse)
err := c.cc.Invoke(ctx, MusicFS_GetStatus_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*Empty, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Empty)
err := c.cc.Invoke(ctx, MusicFS_Shutdown_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) GetCacheStats(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*CacheStats, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CacheStats)
err := c.cc.Invoke(ctx, MusicFS_GetCacheStats_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) ClearCache(ctx context.Context, in *ClearCacheRequest, opts ...grpc.CallOption) (*ClearCacheResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ClearCacheResponse)
err := c.cc.Invoke(ctx, MusicFS_ClearCache_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) Prefetch(ctx context.Context, in *PrefetchRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[PrefetchProgress], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &MusicFS_ServiceDesc.Streams[1], MusicFS_Prefetch_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[PrefetchRequest, PrefetchProgress]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_PrefetchClient = grpc.ServerStreamingClient[PrefetchProgress]
func (c *musicFSClient) ListOrigins(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*OriginsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OriginsResponse)
err := c.cc.Invoke(ctx, MusicFS_ListOrigins_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) GetOriginHealth(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (*OriginHealthResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OriginHealthResponse)
err := c.cc.Invoke(ctx, MusicFS_GetOriginHealth_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *musicFSClient) RescanOrigin(ctx context.Context, in *OriginRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[SyncProgress], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &MusicFS_ServiceDesc.Streams[2], MusicFS_RescanOrigin_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[OriginRequest, SyncProgress]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_RescanOriginClient = grpc.ServerStreamingClient[SyncProgress]
func (c *musicFSClient) SubscribeEvents(ctx context.Context, in *EventFilter, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Event], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &MusicFS_ServiceDesc.Streams[3], MusicFS_SubscribeEvents_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[EventFilter, Event]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_SubscribeEventsClient = grpc.ServerStreamingClient[Event]
// MusicFSServer is the server API for MusicFS service.
// All implementations must embed UnimplementedMusicFSServer
// for forward compatibility.
type MusicFSServer interface {
Search(context.Context, *SearchRequest) (*SearchResponse, error)
SearchStream(*SearchRequest, grpc.ServerStreamingServer[SearchResult]) error
GetStatus(context.Context, *Empty) (*StatusResponse, error)
Shutdown(context.Context, *ShutdownRequest) (*Empty, error)
GetCacheStats(context.Context, *Empty) (*CacheStats, error)
ClearCache(context.Context, *ClearCacheRequest) (*ClearCacheResponse, error)
Prefetch(*PrefetchRequest, grpc.ServerStreamingServer[PrefetchProgress]) error
ListOrigins(context.Context, *Empty) (*OriginsResponse, error)
GetOriginHealth(context.Context, *OriginRequest) (*OriginHealthResponse, error)
RescanOrigin(*OriginRequest, grpc.ServerStreamingServer[SyncProgress]) error
SubscribeEvents(*EventFilter, grpc.ServerStreamingServer[Event]) error
mustEmbedUnimplementedMusicFSServer()
}
// UnimplementedMusicFSServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMusicFSServer struct{}
func (UnimplementedMusicFSServer) Search(context.Context, *SearchRequest) (*SearchResponse, error) {
return nil, status.Error(codes.Unimplemented, "method Search not implemented")
}
func (UnimplementedMusicFSServer) SearchStream(*SearchRequest, grpc.ServerStreamingServer[SearchResult]) error {
return status.Error(codes.Unimplemented, "method SearchStream not implemented")
}
func (UnimplementedMusicFSServer) GetStatus(context.Context, *Empty) (*StatusResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetStatus not implemented")
}
func (UnimplementedMusicFSServer) Shutdown(context.Context, *ShutdownRequest) (*Empty, error) {
return nil, status.Error(codes.Unimplemented, "method Shutdown not implemented")
}
func (UnimplementedMusicFSServer) GetCacheStats(context.Context, *Empty) (*CacheStats, error) {
return nil, status.Error(codes.Unimplemented, "method GetCacheStats not implemented")
}
func (UnimplementedMusicFSServer) ClearCache(context.Context, *ClearCacheRequest) (*ClearCacheResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ClearCache not implemented")
}
func (UnimplementedMusicFSServer) Prefetch(*PrefetchRequest, grpc.ServerStreamingServer[PrefetchProgress]) error {
return status.Error(codes.Unimplemented, "method Prefetch not implemented")
}
func (UnimplementedMusicFSServer) ListOrigins(context.Context, *Empty) (*OriginsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ListOrigins not implemented")
}
func (UnimplementedMusicFSServer) GetOriginHealth(context.Context, *OriginRequest) (*OriginHealthResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetOriginHealth not implemented")
}
func (UnimplementedMusicFSServer) RescanOrigin(*OriginRequest, grpc.ServerStreamingServer[SyncProgress]) error {
return status.Error(codes.Unimplemented, "method RescanOrigin not implemented")
}
func (UnimplementedMusicFSServer) SubscribeEvents(*EventFilter, grpc.ServerStreamingServer[Event]) error {
return status.Error(codes.Unimplemented, "method SubscribeEvents not implemented")
}
func (UnimplementedMusicFSServer) mustEmbedUnimplementedMusicFSServer() {}
func (UnimplementedMusicFSServer) testEmbeddedByValue() {}
// UnsafeMusicFSServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MusicFSServer will
// result in compilation errors.
type UnsafeMusicFSServer interface {
mustEmbedUnimplementedMusicFSServer()
}
func RegisterMusicFSServer(s grpc.ServiceRegistrar, srv MusicFSServer) {
// If the following call panics, it indicates UnimplementedMusicFSServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&MusicFS_ServiceDesc, srv)
}
func _MusicFS_Search_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).Search(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_Search_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).Search(ctx, req.(*SearchRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_SearchStream_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(SearchRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(MusicFSServer).SearchStream(m, &grpc.GenericServerStream[SearchRequest, SearchResult]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_SearchStreamServer = grpc.ServerStreamingServer[SearchResult]
func _MusicFS_GetStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).GetStatus(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_GetStatus_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).GetStatus(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_Shutdown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ShutdownRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).Shutdown(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_Shutdown_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).Shutdown(ctx, req.(*ShutdownRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_GetCacheStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).GetCacheStats(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_GetCacheStats_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).GetCacheStats(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_ClearCache_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClearCacheRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).ClearCache(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_ClearCache_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).ClearCache(ctx, req.(*ClearCacheRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_Prefetch_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(PrefetchRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(MusicFSServer).Prefetch(m, &grpc.GenericServerStream[PrefetchRequest, PrefetchProgress]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_PrefetchServer = grpc.ServerStreamingServer[PrefetchProgress]
func _MusicFS_ListOrigins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).ListOrigins(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_ListOrigins_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).ListOrigins(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_GetOriginHealth_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(OriginRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MusicFSServer).GetOriginHealth(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MusicFS_GetOriginHealth_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MusicFSServer).GetOriginHealth(ctx, req.(*OriginRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MusicFS_RescanOrigin_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(OriginRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(MusicFSServer).RescanOrigin(m, &grpc.GenericServerStream[OriginRequest, SyncProgress]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_RescanOriginServer = grpc.ServerStreamingServer[SyncProgress]
func _MusicFS_SubscribeEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(EventFilter)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(MusicFSServer).SubscribeEvents(m, &grpc.GenericServerStream[EventFilter, Event]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MusicFS_SubscribeEventsServer = grpc.ServerStreamingServer[Event]
// MusicFS_ServiceDesc is the grpc.ServiceDesc for MusicFS service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var MusicFS_ServiceDesc = grpc.ServiceDesc{
ServiceName: "musicfs.v1.MusicFS",
HandlerType: (*MusicFSServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Search",
Handler: _MusicFS_Search_Handler,
},
{
MethodName: "GetStatus",
Handler: _MusicFS_GetStatus_Handler,
},
{
MethodName: "Shutdown",
Handler: _MusicFS_Shutdown_Handler,
},
{
MethodName: "GetCacheStats",
Handler: _MusicFS_GetCacheStats_Handler,
},
{
MethodName: "ClearCache",
Handler: _MusicFS_ClearCache_Handler,
},
{
MethodName: "ListOrigins",
Handler: _MusicFS_ListOrigins_Handler,
},
{
MethodName: "GetOriginHealth",
Handler: _MusicFS_GetOriginHealth_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "SearchStream",
Handler: _MusicFS_SearchStream_Handler,
ServerStreams: true,
},
{
StreamName: "Prefetch",
Handler: _MusicFS_Prefetch_Handler,
ServerStreams: true,
},
{
StreamName: "RescanOrigin",
Handler: _MusicFS_RescanOrigin_Handler,
ServerStreams: true,
},
{
StreamName: "SubscribeEvents",
Handler: _MusicFS_SubscribeEvents_Handler,
ServerStreams: true,
},
},
Metadata: "musicfs.proto",
}
const (
MetadataService_GetMetadata_FullMethodName = "/musicfs.v1.MetadataService/GetMetadata"
MetadataService_UpdateMetadata_FullMethodName = "/musicfs.v1.MetadataService/UpdateMetadata"
MetadataService_ClearOverlay_FullMethodName = "/musicfs.v1.MetadataService/ClearOverlay"
MetadataService_BatchUpdateMetadata_FullMethodName = "/musicfs.v1.MetadataService/BatchUpdateMetadata"
MetadataService_ImportMetadata_FullMethodName = "/musicfs.v1.MetadataService/ImportMetadata"
)
// MetadataServiceClient is the client API for MetadataService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type MetadataServiceClient interface {
GetMetadata(ctx context.Context, in *GetMetadataRequest, opts ...grpc.CallOption) (*MetadataResponse, error)
UpdateMetadata(ctx context.Context, in *UpdateMetadataRequest, opts ...grpc.CallOption) (*UpdateMetadataResponse, error)
ClearOverlay(ctx context.Context, in *ClearOverlayRequest, opts ...grpc.CallOption) (*ClearOverlayResponse, error)
BatchUpdateMetadata(ctx context.Context, in *BatchUpdateRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[BatchUpdateProgress], error)
ImportMetadata(ctx context.Context, in *ImportMetadataRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImportProgress], error)
}
type metadataServiceClient struct {
cc grpc.ClientConnInterface
}
func NewMetadataServiceClient(cc grpc.ClientConnInterface) MetadataServiceClient {
return &metadataServiceClient{cc}
}
func (c *metadataServiceClient) GetMetadata(ctx context.Context, in *GetMetadataRequest, opts ...grpc.CallOption) (*MetadataResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(MetadataResponse)
err := c.cc.Invoke(ctx, MetadataService_GetMetadata_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *metadataServiceClient) UpdateMetadata(ctx context.Context, in *UpdateMetadataRequest, opts ...grpc.CallOption) (*UpdateMetadataResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UpdateMetadataResponse)
err := c.cc.Invoke(ctx, MetadataService_UpdateMetadata_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *metadataServiceClient) ClearOverlay(ctx context.Context, in *ClearOverlayRequest, opts ...grpc.CallOption) (*ClearOverlayResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ClearOverlayResponse)
err := c.cc.Invoke(ctx, MetadataService_ClearOverlay_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *metadataServiceClient) BatchUpdateMetadata(ctx context.Context, in *BatchUpdateRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[BatchUpdateProgress], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &MetadataService_ServiceDesc.Streams[0], MetadataService_BatchUpdateMetadata_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[BatchUpdateRequest, BatchUpdateProgress]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MetadataService_BatchUpdateMetadataClient = grpc.ServerStreamingClient[BatchUpdateProgress]
func (c *metadataServiceClient) ImportMetadata(ctx context.Context, in *ImportMetadataRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ImportProgress], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &MetadataService_ServiceDesc.Streams[1], MetadataService_ImportMetadata_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[ImportMetadataRequest, ImportProgress]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MetadataService_ImportMetadataClient = grpc.ServerStreamingClient[ImportProgress]
// MetadataServiceServer is the server API for MetadataService service.
// All implementations must embed UnimplementedMetadataServiceServer
// for forward compatibility.
type MetadataServiceServer interface {
GetMetadata(context.Context, *GetMetadataRequest) (*MetadataResponse, error)
UpdateMetadata(context.Context, *UpdateMetadataRequest) (*UpdateMetadataResponse, error)
ClearOverlay(context.Context, *ClearOverlayRequest) (*ClearOverlayResponse, error)
BatchUpdateMetadata(*BatchUpdateRequest, grpc.ServerStreamingServer[BatchUpdateProgress]) error
ImportMetadata(*ImportMetadataRequest, grpc.ServerStreamingServer[ImportProgress]) error
mustEmbedUnimplementedMetadataServiceServer()
}
// UnimplementedMetadataServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedMetadataServiceServer struct{}
func (UnimplementedMetadataServiceServer) GetMetadata(context.Context, *GetMetadataRequest) (*MetadataResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetMetadata not implemented")
}
func (UnimplementedMetadataServiceServer) UpdateMetadata(context.Context, *UpdateMetadataRequest) (*UpdateMetadataResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateMetadata not implemented")
}
func (UnimplementedMetadataServiceServer) ClearOverlay(context.Context, *ClearOverlayRequest) (*ClearOverlayResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ClearOverlay not implemented")
}
func (UnimplementedMetadataServiceServer) BatchUpdateMetadata(*BatchUpdateRequest, grpc.ServerStreamingServer[BatchUpdateProgress]) error {
return status.Error(codes.Unimplemented, "method BatchUpdateMetadata not implemented")
}
func (UnimplementedMetadataServiceServer) ImportMetadata(*ImportMetadataRequest, grpc.ServerStreamingServer[ImportProgress]) error {
return status.Error(codes.Unimplemented, "method ImportMetadata not implemented")
}
func (UnimplementedMetadataServiceServer) mustEmbedUnimplementedMetadataServiceServer() {}
func (UnimplementedMetadataServiceServer) testEmbeddedByValue() {}
// UnsafeMetadataServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to MetadataServiceServer will
// result in compilation errors.
type UnsafeMetadataServiceServer interface {
mustEmbedUnimplementedMetadataServiceServer()
}
func RegisterMetadataServiceServer(s grpc.ServiceRegistrar, srv MetadataServiceServer) {
// If the following call panics, it indicates UnimplementedMetadataServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&MetadataService_ServiceDesc, srv)
}
func _MetadataService_GetMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetMetadataRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MetadataServiceServer).GetMetadata(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MetadataService_GetMetadata_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MetadataServiceServer).GetMetadata(ctx, req.(*GetMetadataRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MetadataService_UpdateMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateMetadataRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MetadataServiceServer).UpdateMetadata(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MetadataService_UpdateMetadata_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MetadataServiceServer).UpdateMetadata(ctx, req.(*UpdateMetadataRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MetadataService_ClearOverlay_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClearOverlayRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MetadataServiceServer).ClearOverlay(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: MetadataService_ClearOverlay_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MetadataServiceServer).ClearOverlay(ctx, req.(*ClearOverlayRequest))
}
return interceptor(ctx, in, info, handler)
}
func _MetadataService_BatchUpdateMetadata_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(BatchUpdateRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(MetadataServiceServer).BatchUpdateMetadata(m, &grpc.GenericServerStream[BatchUpdateRequest, BatchUpdateProgress]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MetadataService_BatchUpdateMetadataServer = grpc.ServerStreamingServer[BatchUpdateProgress]
func _MetadataService_ImportMetadata_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(ImportMetadataRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(MetadataServiceServer).ImportMetadata(m, &grpc.GenericServerStream[ImportMetadataRequest, ImportProgress]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type MetadataService_ImportMetadataServer = grpc.ServerStreamingServer[ImportProgress]
// MetadataService_ServiceDesc is the grpc.ServiceDesc for MetadataService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var MetadataService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "musicfs.v1.MetadataService",
HandlerType: (*MetadataServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetMetadata",
Handler: _MetadataService_GetMetadata_Handler,
},
{
MethodName: "UpdateMetadata",
Handler: _MetadataService_UpdateMetadata_Handler,
},
{
MethodName: "ClearOverlay",
Handler: _MetadataService_ClearOverlay_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "BatchUpdateMetadata",
Handler: _MetadataService_BatchUpdateMetadata_Handler,
ServerStreams: true,
},
{
StreamName: "ImportMetadata",
Handler: _MetadataService_ImportMetadata_Handler,
ServerStreams: true,
},
},
Metadata: "musicfs.proto",
}
+135
View File
@@ -0,0 +1,135 @@
package matcher
import (
"regexp"
"strings"
)
const MatchThreshold = 0.7
var (
punctuationRe = regexp.MustCompile(`[^\w\s]`)
yearRe = regexp.MustCompile(`\b(19|20)\d{2}\b`)
whitespaceRe = regexp.MustCompile(`\s+`)
noiseWords = map[string]struct{}{
"remastered": {}, "remaster": {}, "deluxe": {}, "edition": {},
"expanded": {}, "anniversary": {}, "special": {}, "limited": {},
"collectors": {}, "collector": {}, "bonus": {}, "tracks": {},
"standard": {}, "super": {},
"flac": {}, "mp3": {}, "aac": {}, "ogg": {}, "wav": {},
"24bit": {}, "16bit": {}, "48khz": {}, "44khz": {}, "96khz": {}, "192khz": {},
"cd": {}, "vinyl": {}, "lp": {}, "web": {}, "sacd": {},
"box": {}, "set": {}, "japan": {}, "shm": {},
"singles": {}, "single": {},
"pmedia": {},
}
)
func normalize(s string) string {
s = strings.ToLower(s)
s = punctuationRe.ReplaceAllString(s, " ")
s = yearRe.ReplaceAllString(s, " ")
s = whitespaceRe.ReplaceAllString(s, " ")
return strings.TrimSpace(s)
}
func tokenize(s string) []string {
var tokens []string
for _, word := range strings.Fields(s) {
if _, noise := noiseWords[word]; !noise && len(word) > 1 {
tokens = append(tokens, word)
}
}
return tokens
}
func AlbumMatchScore(albumTitle, torrentTitle, artistName string) float64 {
normAlbum := normalize(albumTitle)
normTorrent := normalize(torrentTitle)
if artistName != "" {
normArtist := normalize(artistName)
normTorrent = strings.Replace(normTorrent, normArtist, "", 1)
normTorrent = strings.TrimSpace(whitespaceRe.ReplaceAllString(normTorrent, " "))
}
if normAlbum == "" {
return 0
}
if strings.Contains(normTorrent, normAlbum) {
return 1.0
}
albumTokens := tokenize(normAlbum)
if len(albumTokens) == 0 {
return 0
}
torrentTokens := make(map[string]struct{}, len(albumTokens))
for _, t := range tokenize(normTorrent) {
torrentTokens[t] = struct{}{}
}
var matches int
for _, token := range albumTokens {
if _, found := torrentTokens[token]; found {
matches++
continue
}
for tt := range torrentTokens {
if levenshteinClose(token, tt) {
matches++
break
}
}
}
return float64(matches) / float64(len(albumTokens))
}
func levenshteinClose(a, b string) bool {
if len(a) < 3 || len(b) < 3 {
return false
}
maxDist := 1
if len(a) > 6 {
maxDist = 2
}
return levenshtein(a, b) <= maxDist
}
func levenshtein(a, b string) int {
la, lb := len(a), len(b)
if la == 0 {
return lb
}
if lb == 0 {
return la
}
prev := make([]int, lb+1)
curr := make([]int, lb+1)
for j := 0; j <= lb; j++ {
prev[j] = j
}
for i := 1; i <= la; i++ {
curr[0] = i
for j := 1; j <= lb; j++ {
cost := 1
if a[i-1] == b[j-1] {
cost = 0
}
curr[j] = min(curr[j-1]+1, min(prev[j]+1, prev[j-1]+cost))
}
prev, curr = curr, prev
}
return prev[lb]
}
func IsAlbumMatch(albumTitle, torrentTitle, artistName string) bool {
return AlbumMatchScore(albumTitle, torrentTitle, artistName) >= MatchThreshold
}
+95
View File
@@ -0,0 +1,95 @@
package matcher
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAlbumMatchScore(t *testing.T) {
tests := []struct {
album string
torrent string
artist string
wantMin float64
wantMax float64
match bool
}{
{
album: "Ain't My Bitch",
torrent: "Metallica - Ain't My Bitch (2025) [FLAC]",
artist: "Metallica",
wantMin: 0.9, wantMax: 1.0, match: true,
},
{
album: "Ain't My Bitch",
torrent: "Metallica - Aint My Bitch Remastered 2025 FLAC",
artist: "Metallica",
wantMin: 0.9, wantMax: 1.0, match: true,
},
{
album: "72 Seasons",
torrent: "Metallica - 72 Seasons (2023) [24Bit-48kHz] FLAC [PMEDIA] ⭐️",
artist: "Metallica",
wantMin: 0.9, wantMax: 1.0, match: true,
},
{
album: "Kill 'Em All",
torrent: "Metallica - Kill Em All [1983] FLAC",
artist: "Metallica",
wantMin: 0.9, wantMax: 1.0, match: true,
},
{
album: "...And Justice for All",
torrent: "Metallica - And Justice For All (Remastered) FLAC",
artist: "Metallica",
wantMin: 0.7, wantMax: 1.0, match: true,
},
{
album: "Master of Puppets",
torrent: "Metallica - Master of Puppets (Remastered Deluxe Box Set) FLAC",
artist: "Metallica",
wantMin: 0.9, wantMax: 1.0, match: true,
},
{
album: "Ain't My Bitch",
torrent: "Metallica - Load 1996 (Japan SHM-CD)",
artist: "Metallica",
wantMin: 0.0, wantMax: 0.3, match: false,
},
{
album: "Ain't My Bitch",
torrent: "Metallica - The Memory Remains (Singles, 2026 remastered)",
artist: "Metallica",
wantMin: 0.0, wantMax: 0.3, match: false,
},
{
album: "Ain't My Bitch",
torrent: "Metallica - 72 Seasons (2023) [24Bit-48kHz] FLAC",
artist: "Metallica",
wantMin: 0.0, wantMax: 0.3, match: false,
},
{
album: "Hardwired...to Self-Destruct",
torrent: "Metallica - Hardwired To Self-Destruct (Deluxe 2016) [FLAC]",
artist: "Metallica",
wantMin: 0.7, wantMax: 1.0, match: true,
},
{
album: "S&M",
torrent: "Metallica - S&M (1999) [FLAC]",
artist: "Metallica",
wantMin: 0.9, wantMax: 1.0, match: true,
},
}
for _, tt := range tests {
t.Run(tt.album+" vs "+tt.torrent, func(t *testing.T) {
score := AlbumMatchScore(tt.album, tt.torrent, tt.artist)
assert.GreaterOrEqual(t, score, tt.wantMin, "score too low: %.2f", score)
assert.LessOrEqual(t, score, tt.wantMax, "score too high: %.2f", score)
assert.Equal(t, tt.match, IsAlbumMatch(tt.album, tt.torrent, tt.artist),
"match mismatch for score %.2f", score)
})
}
}