package plugin import ( "errors" "regexp" "gitea.elara.ws/Hazel/music-kraken/internal/data" ) type Plugin interface { Name() string Regex() *regexp.Regexp RegexArtist() *regexp.Regexp RegexAlbum() *regexp.Regexp RegexSong() *regexp.Regexp Search(query string) ([]data.MusicObject, error) FetchArtist(source data.Source) (data.Artist, error) FetchAlbum(source data.Source) (data.Album, error) FetchSong(source data.Source) (data.Song, error) } var namePlugins = map[string]Plugin{} var nameSourceType = map[string]data.SourceType{} func RegisterPlugin(plugin Plugin) error { name := plugin.Name() if _, ok := namePlugins[name]; ok { return errors.New("plugin " + name + " is already registered") } nameSourceType[name] = data.SourceType{ Name: name, Regex: plugin.Regex(), RegexArtist: plugin.RegexArtist(), RegexAlbum: plugin.RegexAlbum(), RegexSong: plugin.RegexSong(), } namePlugins[name] = plugin return nil } func compileSourceType(source data.Source) (data.Source, error) { if source.SourceType != nil { return source, nil } for _, st := range nameSourceType { if m := st.Regex.FindString(source.Url); m != "" { source.Url = m source.SourceType = &st return source, nil } } return source, errors.New("couldn't find source type for " + source.Url) } func compileSource(source data.Source) (data.Source, error) { source, err := compileSourceType(source) if err != nil { return source, err } // find what object this source corresponds to if source.ObjectType != "" { return source, nil } sourceType := source.SourceType if sourceType.RegexSong.MatchString(source.Url) { source.ObjectType = data.SongSource return source, nil } if sourceType.RegexAlbum.MatchString(source.Url) { source.ObjectType = data.AlbumSource return source, nil } if sourceType.RegexArtist.MatchString(source.Url) { source.ObjectType = data.ArtistSource return source, nil } return source, errors.New("couldn't find corresponding object source on " + sourceType.Name + " for " + source.Url) } func Fetch(source data.Source) (data.MusicObject, error) { // the fetch function without the post processing of the music objects source, err := compileSource(source) if err != nil { return nil, err } plugin, ok := namePlugins[source.SourceType.Name] if !ok { return nil, errors.New("didn't find plugin of the name " + source.SourceType.Name) } if source.ObjectType == data.SongSource { song, err := plugin.FetchSong(source) if err != nil { return song, err } song.Sources = append(song.Sources, source) song = song.Compile().(data.Song) return song, nil } if source.ObjectType == data.AlbumSource { album, err := plugin.FetchAlbum(source) if err != nil { return album, err } album.Sources = append(album.Sources, source) album = album.Compile().(data.Album) return album, nil } if source.ObjectType == data.ArtistSource { artist, err := plugin.FetchArtist(source) if err != nil { return artist, err } artist.Sources = append(artist.Sources, source) artist = artist.Compile().(data.Artist) return artist, nil } return nil, nil }