Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Ableton source file parsing #78

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AUTHORS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions api/sgtm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ message Post {
string provider_metadata = 50;
string tags = 51; // comma separated list of tags
string lyrics = 52;
string daw_name = 54;
int64 tracks_number = 55;
string plugins = 56;

/// soundcloud post

Expand Down
4 changes: 2 additions & 2 deletions gen.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 31 additions & 11 deletions pkg/sgtm/page_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,33 @@ func (svc *Service) newPage(box *packr.Box) func(w http.ResponseWriter, r *http.
data.Error = err.Error()
return nil
}

// TODO: run mimetype detection on file maybe
filenameParts := strings.Split(header.Filename, ".")
ext := "blob"
filename := header.Filename
numParts := len(filenameParts)
if numParts >= 2 {
ext = filenameParts[numParts-1]
filename = strings.Join(filenameParts[:numParts-1], ".")
}

var trackInfos = &TrackSourceFile{
Daw: "",
Tracks: 0,
Plugins: []string{},
}
// TODO: move to an async worker
// TODO: parse other source file extensions
if ext == "als" {
trackInfos, err = ExtractAbletonTrackInfos(file)
if err != nil {
data.Error = err.Error()
return nil
}
}
fmt.Println("trackInfos", trackInfos)

defer file.Close()

fmt.Println("header", header.Header)
Expand All @@ -58,7 +85,7 @@ func (svc *Service) newPage(box *packr.Box) func(w http.ResponseWriter, r *http.
data.Error = err.Error()
return nil
}
fmt.Println("done uploading to ipfs")
fmt.Println("done uploading to ipfs: ", cid)

// check if track already exists
{
Expand All @@ -78,16 +105,6 @@ func (svc *Service) newPage(box *packr.Box) func(w http.ResponseWriter, r *http.
fmt.Println("MIME", mimeType)
// FIXME: check that mimeType starts with audio/ maybe

// TODO: run mimetype detection on file maybe
filenameParts := strings.Split(header.Filename, ".")
ext := "blob"
filename := header.Filename
numParts := len(filenameParts)
if numParts >= 2 {
ext = filenameParts[numParts-1]
filename = strings.Join(filenameParts[:numParts-1], ".")
}

return &sgtmpb.Post{
Kind: sgtmpb.Post_TrackKind,
Visibility: sgtmpb.Visibility_Public,
Expand All @@ -102,6 +119,9 @@ func (svc *Service) newPage(box *packr.Box) func(w http.ResponseWriter, r *http.
SizeBytes: header.Size,
FileExtension: ext,
AttachmentFilename: header.Filename,
DawName: trackInfos.Daw,
Plugins: strings.Join(trackInfos.Plugins, ","),
TracksNumber: int64(trackInfos.Tracks),
}
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/sgtm/page_post.tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ <h1>{{.Post.Post.SafeTitle}}</h1>
<div>⬇️ <a download="{{.Post.Post.SafeTitle}}.{{.Post.Post.FileExtension}}" href="/post/{{ .Post.Post.ID }}/download">Download</a></div>
<div style="word-break: break-all;">⚓ IPFS CID: {{ .Post.Post.IPFSCID }}</div>
{{end}}
{{if .Post.Post.IsSource}}
<div>💻 DAW: {{ .Post.Post.DawName }}</div>
<div>🔌️ Plugins: {{ .Post.Post.Plugins }}</div>
<div>Number of tracks: {{ .Post.Post.TracksNumber }}</div>
{{end}}

<!--{{with .Post.Post.DownloadURL}}<div><a href="{{.}}" class="btn">⬇️ Download</a></div>{{end}}-->
<div>📆 Added <span data-toggle="tooltip" data-placement="right" title="{{.Post.Post.SortDate | fromUnixNano | prettyDate}}">{{.Post.Post.SortDate | fromUnixNano | prettyAgo}}</span></div>
<!--<div><span class="fa fa-soundcloud"></span> {{.Post.Post.URL}}</div>-->
Expand Down
65 changes: 65 additions & 0 deletions pkg/sgtm/processing.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sgtm

import (
"compress/gzip"
"context"
"encoding/csv"
"encoding/json"
Expand All @@ -14,6 +15,7 @@ import (
"strings"
"time"

"github.com/beevik/etree"
"moul.io/sgtm/pkg/sgtmpb"
)

Expand Down Expand Up @@ -125,6 +127,69 @@ func ExtractBPM(p string) (float64, error) {
return average, nil
}

type TrackSourceFile struct {
Daw string
Tracks int
Plugins []string
}

func ExtractAbletonTrackInfos(fileReader io.Reader) (*TrackSourceFile, error) {
uncompressedStream, err := gzip.NewReader(fileReader)
if err != nil {
return nil, err
}
defer uncompressedStream.Close()

fileContents, err := ioutil.ReadAll(uncompressedStream)
if err != nil {
return nil, err
}

doc := etree.NewDocument()
if err := doc.ReadFromBytes(fileContents); err != nil {
panic(err)
}

daw := doc.Root().SelectAttr("Creator").Value
tracks := doc.Root().FindElement("LiveSet/Tracks")
midiTracks := tracks.FindElements("MidiTrack")
audioTracks := tracks.FindElements("AudioTrack")
nbTracks := len(midiTracks) + len(audioTracks)

plugins := make([]string, 0)
for _, track := range midiTracks {
plugins = append(plugins, findPlugins(track)...)
}
for _, track := range audioTracks {
plugins = append(plugins, findPlugins(track)...)
}

return &TrackSourceFile{
Daw: daw,
Tracks: nbTracks,
Plugins: unique(plugins),
}, nil
}

func findPlugins(track *etree.Element) []string {
devices := track.FindElements("DeviceChain/DeviceChain/Devices")
if devices == nil {
return nil
}

plugins := make([]string, 0, len(devices))
for _, device := range devices {
pluginDevice := device.FindElement("PluginDevice/PluginDesc/VstPluginInfo/PlugName")
if pluginDevice == nil {
continue
}
pluginName := pluginDevice.SelectAttr("Value")
plugins = append(plugins, pluginName.Value)
}

return plugins
}

type YoutubeDLOutput struct {
Extractor string `json:"extractor"`
Protocol string `json:"protocol"`
Expand Down
47 changes: 47 additions & 0 deletions pkg/sgtm/processing_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package sgtm

import (
"io"
"log"
"os"
"reflect"
"testing"
)

func TestExtractAbletonTrackInfos(t *testing.T) {
file, err := os.Open("../../test/TestTrack.als")
if err != nil {
log.Fatal(err)
}

type args struct {
fileReader io.Reader
}
tests := []struct {
name string
args args
want *TrackSourceFile
wantErr bool
}{
{"should parse a correct ableton file",
args{fileReader: file},
&TrackSourceFile{
Daw: "Ableton Live 10.0.4",
Tracks: 26,
Plugins: []string{"Serum", "BalanceSPTeufelsbergReverb", "FabFilter Pro-Q 2", "Auburn Sounds Graillon 2"},
},
false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ExtractAbletonTrackInfos(tt.args.fileReader)
if (err != nil) != tt.wantErr {
t.Errorf("ExtractAbletonTrackInfos() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtractAbletonTrackInfos() got = %v, want %v", got, tt.want)
}
})
}
}
12 changes: 12 additions & 0 deletions pkg/sgtm/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,15 @@ func pathExists(p string) bool {
_, err := os.Stat(p)
return !os.IsNotExist(err)
}

func unique(intSlice []string) []string {
keys := make(map[string]bool)
list := []string{}
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
2 changes: 2 additions & 0 deletions pkg/sgtmpb/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ func (p *Post) Filter() {
func (p *Post) IsSoundCloud() bool { return p.GetProvider() == Provider_SoundCloud }
func (p *Post) IsIPFS() bool { return p.GetProvider() == Provider_IPFS }

func (p *Post) IsSource() bool { return p.GetDawName() != "" }

func (p *Post) TagList() []string {
if strings.TrimSpace(p.Tags) == "" {
return nil
Expand Down
Loading