Compare commits

..

7 Commits

Author SHA1 Message Date
acute_interpreter_panic
964512de06 fixed pointer issue 2025-10-10 14:36:33 +02:00
acute_interpreter_panic
87e276de3d very slim skelleton for downloading 2025-10-10 14:07:03 +02:00
acute_interpreter_panic
04e8378f3f improved shell 2025-10-10 13:45:27 +02:00
acute_interpreter_panic
293de8b473 scraping audio url 2025-10-10 13:44:00 +02:00
acute_interpreter_panic
82c541653c added audio url to datatype 2025-10-10 13:25:29 +02:00
acute_interpreter_panic
1ff37517a5 test 2025-10-10 13:21:04 +02:00
acute_interpreter_panic
c7fceb277d added running of commands 2025-10-10 13:19:32 +02:00
6 changed files with 201 additions and 29 deletions

View File

@@ -50,6 +50,9 @@ func printResults(musicObjects []data.MusicObject) {
if len(sources) > 0 {
for _, source := range sources {
results[i] += "\n\t- " + source.SourceType.Name + " " + string(source.ObjectType) + " " + source.Url
if source.AudioUrl != "" {
results[i] += "\n\t " + source.AudioUrl
}
}
} else {
results[i] = color.StrikeThrough + results[i] + color.Reset
@@ -73,21 +76,29 @@ func (s musicObjectStore) currentMusicObjects() ([]data.MusicObject, error) {
var indexSelectionPattern = regexp.MustCompile(`^[\d ,]+$`)
func interpretCommand(command string, store musicObjectStore) (musicObjectStore, error) {
func interpretCommand(command string, store musicObjectStore) (musicObjectStore, []error) {
// going back in history
if command == ".." {
if len(store) <= 1 {
return store, errors.New("can't go back")
return store, []error{errors.New("can't go back")}
}
return store[:len(store)-1], nil
return store[:len(store)-1], []error{}
}
forceDownload := false
if strings.HasPrefix(command, "d:") {
command, _ = strings.CutPrefix(command, "d:")
command = strings.TrimSpace(command)
forceDownload = true
}
// fetch special music object
if indexSelectionPattern.MatchString(command) {
currentMusicObjects, err := store.currentMusicObjects()
if err != nil {
return store, err
return store, []error{err}
}
var fetched data.MusicObject
@@ -96,14 +107,14 @@ func interpretCommand(command string, store musicObjectStore) (musicObjectStore,
index, _ := strconv.Atoi(strings.TrimSpace(stringIndex))
if index >= len(currentMusicObjects) || index < 0 {
return store, errors.New(command + " is out of bounds [0 <= " + strconv.Itoa(index) + " <= " + strconv.Itoa(len(currentMusicObjects)-1) + "]")
return store, []error{errors.New(command + " is out of bounds [0 <= " + strconv.Itoa(index) + " <= " + strconv.Itoa(len(currentMusicObjects)-1) + "]")}
}
current := currentMusicObjects[index]
newFetched, err := plugin.Fetch(current)
if err != nil {
return store, err
return store, []error{err}
}
if fetched == nil {
@@ -113,7 +124,13 @@ func interpretCommand(command string, store musicObjectStore) (musicObjectStore,
}
}
return append(store, fetched.Related()), nil
if forceDownload {
return store, plugin.Download(fetched)
} else {
return append(store, fetched.Related()), []error{}
}
} else if forceDownload {
return store, []error{errors.New("can only download indices not " + command)}
}
// search in every other case
@@ -123,30 +140,48 @@ func interpretCommand(command string, store musicObjectStore) (musicObjectStore,
fmt.Println()
}
return append(store, currentMusicObjects), nil
return append(store, currentMusicObjects), []error{}
}
func Shell() {
func Shell(commandsList ...[]string) {
plugin.RegisterPlugin(&plugin.Musify{})
commands := []string{}
if len(commandsList) > 0 {
commands = commandsList[0]
}
fmt.Println("== MusicKraken Shell ==")
fmt.Println()
store := musicObjectStore{}
var err error = nil
for {
fmt.Print("> ")
var command string
reader := bufio.NewReader(os.Stdin)
command, err := reader.ReadString('\n')
if err != nil {
log.Fatal(err)
if len(commands) <= 0 {
fmt.Print("> ")
reader := bufio.NewReader(os.Stdin)
command, err = reader.ReadString('\n')
if err != nil {
log.Fatal(err)
}
} else {
command = commands[0]
commands = commands[1:]
fmt.Println("> " + command)
}
store, err = interpretCommand(strings.TrimSpace(command), store)
if err != nil {
var errList []error
store, errList = interpretCommand(strings.TrimSpace(command), store)
if len(errList) > 0 {
fmt.Println()
fmt.Println(color.Yellow + err.Error() + color.Reset)
for _, err := range errList {
fmt.Println(color.Yellow + err.Error() + color.Reset)
}
fmt.Println()
}

View File

@@ -24,7 +24,7 @@ func ZeroPad(num int, length int) string {
func IsNumeric(num string) bool {
for _, c := range num {
if c >= '0' && c <= '9' {
if c < '0' || c > '9' {
return false
}
}
@@ -84,7 +84,7 @@ func CleanSongTitle(title string, artistName string) string {
title = strings.TrimSpace(title)
for _, d := range commonTitleSuffix {
if strings.HasSuffix(strings.ToLower(d), d) {
if strings.HasSuffix(strings.ToLower(title), d) {
title = strings.TrimSpace(title[:len(d)-1])
}
}

View File

@@ -19,7 +19,9 @@ const AlbumSource = ObjectType("album")
const ArtistSource = ObjectType("artist")
type Source struct {
Url string
Url string
AudioUrl string // will only be used when ObjectType = SongSource
SourceType *SourceType
ObjectType ObjectType
}
@@ -38,6 +40,9 @@ func dedupeSources(inputSources []Source) []Source {
if source.SourceType != nil {
deduped[mergeWithIndex].SourceType = source.SourceType
}
if source.AudioUrl != "" {
deduped[mergeWithIndex].AudioUrl = source.AudioUrl
}
} else {
// just appending

View File

@@ -2,6 +2,7 @@ package plugin
import (
"errors"
"fmt"
"regexp"
"gitea.elara.ws/Hazel/music-kraken/internal/common"
@@ -163,7 +164,7 @@ func Fetch(musicObject data.MusicObject) (data.MusicObject, error) {
musicObject = musicObject.Merge(newMusicObject)
}
return musicObject, nil
return musicObject.Compile(), nil
}
type SearchConfig struct {
@@ -189,3 +190,93 @@ func Search(search string, config SearchConfig) ([]data.MusicObject, error) {
return res, nil
}
type downloadState struct {
artist *data.Artist
album *data.Album
song *data.Song
}
var variousArtist = data.Artist{
Name: "VariousArtist",
}.Compile().(data.Artist)
var variousAlbum = data.Album{
Name: "VariousAlbum",
}.Compile().(data.Album)
func downloadSong(song data.Song, state downloadState) error {
fmt.Println("downloading: " + song.Name)
return nil
}
func Download(musicObject data.MusicObject, statesInput ...downloadState) []error {
state := downloadState{}
if len(statesInput) > 0 {
state = statesInput[0]
}
musicObject, err := Fetch(musicObject)
if err != nil {
return []error{err}
}
if song, ok := musicObject.(data.Song); ok {
state.song = &song
if state.artist == nil {
if len(song.Artists) > 0 {
state.artist = &song.Artists[0]
} else {
state.artist = &variousArtist
}
}
if state.album == nil {
if song.Album.Name != "" {
state.album = &song.Album
} else {
state.album = &variousAlbum
}
}
err := downloadSong(song, state)
if err == nil {
return []error{}
} else {
return []error{err}
}
}
if album, ok := musicObject.(data.Album); ok {
state.album = &album
if state.artist == nil {
if len(album.Artists) > 0 {
state.artist = &album.Artists[0]
} else {
state.artist = &variousArtist
}
}
errList := []error{}
for _, song := range album.Songs {
errList = append(errList, Download(song, state)...)
}
return errList
}
if artist, ok := musicObject.(data.Artist); ok {
state.artist = &artist
errList := []error{}
for _, album := range artist.Albums {
errList = append(errList, Download(album, state)...)
}
return errList
}
return []error{
errors.New("music object not recognized"),
}
}

View File

@@ -280,6 +280,39 @@ func (m *Musify) Search(query common.Query) ([]data.MusicObject, error) {
return musicObjects, nil
}
type parsedSongUrl struct {
id string
name string
url string
}
func newParsedSongUrl(rawUrl string) (parsedSongUrl, error) {
res := parsedSongUrl{
url: rawUrl,
}
parsed, err := url.Parse(rawUrl)
if err != nil {
return res, err
}
dirs := strings.Split(parsed.Path, "/")
correctPart := dirs[len(dirs)-1]
split := strings.Split(correctPart, "-")
if len(split) < 2 {
return res, errors.New("last part of path has to consist of at least one - " + correctPart)
}
res.id = strings.TrimSpace(split[len(split)-1])
res.name = strings.Join(split[:len(split)-1], "-")
if !common.IsNumeric(res.id) {
return res, errors.New("last elem (id) has to be numeric " + res.id)
}
return res, nil
}
func (m *Musify) FetchSong(source data.Source) (data.Song, error) {
song := data.Song{
Sources: []data.Source{
@@ -298,14 +331,19 @@ func (m *Musify) FetchSong(source data.Source) (data.Song, error) {
}
// Download URL
/*
doc.Find("a[itemprop='audio']").Each(func(i int, anchor *goquery.Selection) {
href, exists := anchor.Attr("href")
if exists {
source.AudioURL = p.host + href
doc.Find("a[itemprop='audio']").Each(func(i int, anchor *goquery.Selection) {
if href, _ := anchor.Attr("href"); true {
// will be the source first added at the begining
song.Sources[0].AudioUrl = musifyHost + href
} else {
// http://musify.club/track/dl/7141298/crystal-f-sekundenschlaf.mp3
parsed, err := newParsedSongUrl(song.Sources[0].Url)
if err != nil {
return
}
})
*/
song.Sources[0].AudioUrl = "http://musify.club/track/dl/" + parsed.id + "/" + parsed.name + ".mp3"
}
})
// Song detail
var listElement *goquery.Selection

View File

@@ -5,5 +5,8 @@ import (
)
func main() {
cli.Shell()
cli.Shell([]string{
"#a Crystal F",
"d: 0",
})
}