Skip to content

Commit

Permalink
Merge pull request #3 from adithayyil/dev
Browse files Browse the repository at this point in the history
v0.5
  • Loading branch information
adithayyil committed May 29, 2024
2 parents e584fb4 + 00239f7 commit b974e13
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 25 deletions.
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# bsdl

A simple BeatStars music downloader built in Go, featuring concurrent downloads and metadata tagging.

## Usage

### Download all tracks from a artist
```shell
bsdl artist lovbug
```
### Download a track from a link
```shell
bsdl track https://www.beatstars.com/beat/lovbug-skoolio-renter_135bpm-15063259
```

## Installation


### MacOS

Install using [Homebrew](https://brew.sh/)

```shell
brew tap adithayyil/bsdl
brew install bsdl
```

### From source

Visit this link to install [Go](https://go.dev/doc/install).

Clone this repo and build
```shell
git clone https://github.com/adithayyil/bsdl.git
cd bsdl
go build
```

After building the project, an executable named `bsdl` is created, which you can then copy to the desired location.

### Pre-compiled
Download the pre-compiled binaries from the releases page and copy them to the desired location.
10 changes: 7 additions & 3 deletions src/artist.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ type ArtistData struct {
Hits []Hit `json:"hits"`
}

func downloadArtistTracks(permalink string) {
func downloadArtistTracks(permalink string, streamOnly bool, threads int) {
if threads < 1 {
log.Fatal("Number of threads must be greater than 1")
}

client := &http.Client{}
log.Println("Retrieving artist tracks...")
tracks := getArtistTracks(permalink, client)
Expand All @@ -63,7 +67,7 @@ func downloadArtistTracks(permalink string) {
p := mpb.New()

// Create a buffered channel to limit the number of concurrent downloads
sem := make(chan struct{}, 10)
sem := make(chan struct{}, threads)

for _, track := range tracks {
wg.Add(1)
Expand All @@ -72,7 +76,7 @@ func downloadArtistTracks(permalink string) {
sem <- struct{}{}

defer wg.Done()
err := downloadFile(track, client, false, p)
err := downloadFile(track, client, false, streamOnly, p)
if err != nil {
log.Printf("Failed to download track: %s by %s. Error: %v\n", track.Title, track.ArtistName, err)
errChan <- err
Expand Down
12 changes: 9 additions & 3 deletions src/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import (

var rootCmd = &cobra.Command{
Use: "bsdl",
Version: "0.0.0",
Version: "0.4",
Short: `BeatStars Music Downloader`,
}

var streamOnly bool
var threads int

var artist = &cobra.Command{
Use: "artist [permalink]",
Aliases: []string{"a"},
Expand All @@ -18,7 +21,7 @@ var artist = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
artistPermalink := args[0]
downloadArtistTracks(artistPermalink)
downloadArtistTracks(artistPermalink, streamOnly, threads)
},
}

Expand All @@ -30,7 +33,7 @@ var track = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
link := args[0]
downloadTrack(link)
downloadTrack(link, streamOnly)
},
}

Expand All @@ -39,6 +42,9 @@ func Execute() {
}

func init() {
artist.PersistentFlags().BoolVar(&streamOnly, "stream-only", false, "Get streams only and don't embed metadata")
artist.PersistentFlags().IntVar(&threads, "threads", 6, "Number of concurrent downloads")
track.PersistentFlags().BoolVar(&streamOnly, "stream-only", false, "Get streams only and don't embed metadata")
rootCmd.AddCommand(artist)
rootCmd.AddCommand(track)
}
29 changes: 12 additions & 17 deletions src/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,27 @@ type Track struct {
Tags []string `json:"tags"`
}

func downloadFile(track Track, client *http.Client, single bool, p *mpb.Progress) error {
func downloadFile(track Track, client *http.Client, single bool, streamOnly bool, p *mpb.Progress) error {
url := track.StreamURL
artistName := track.ArtistName
filename := track.Title

resp, err := client.Get(url)
if err != nil {
return err
}
checkError(err)
defer resp.Body.Close()

bar := p.AddBar(resp.ContentLength,
mpb.PrependDecorators(
decor.Name(fmt.Sprintf("Downloading %s: ", track.Title)),
decor.CountersKibiByte("% .2f / % .2f"),
decor.Name(fmt.Sprintf("Downloading %s •", track.Title)),
),
mpb.AppendDecorators(
decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_MMSS, 60), "Downloaded!"),
decor.Name(" | "),
decor.AverageSpeed(decor.UnitKB, "% .2f"),
),
)

proxyReader := bar.ProxyReader(resp.Body)

bodyBytes, err := io.ReadAll(proxyReader)
if err != nil {
return err
}
checkError(err)

contentType := http.DetectContentType(bodyBytes[:512])
var extension string
Expand All @@ -79,12 +71,15 @@ func downloadFile(track Track, client *http.Client, single bool, p *mpb.Progress
}

filePath := dirPath + "/" + filename + extension
err = os.WriteFile(filePath, bodyBytes, 0644)
if err != nil {
return err
}

embedMetadata(track, filePath)
if streamOnly {
err = os.WriteFile(filePath, bodyBytes, 0644)
checkError(err)
} else {
err = os.WriteFile(filePath, bodyBytes, 0644)
checkError(err)
embedMetadata(track, filePath)
}

return nil
}
Expand Down
4 changes: 2 additions & 2 deletions src/track.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type TrackData struct {
} `json:"response"`
}

func downloadTrack(link string) {
func downloadTrack(link string, streamOnly bool) {
regex := regexp.MustCompile(`/beat/.*?-(\d+)$`)
match := regex.FindStringSubmatch(link)

Expand All @@ -47,7 +47,7 @@ func downloadTrack(link string) {
log.Fatalf("Track from link %s not found\n", link)
} else {
p := mpb.New()
downloadFile(track, client, true, p)
downloadFile(track, client, true, streamOnly, p)

fmt.Println()
log.Printf("Downloaded %s by %s\n", track.Title, track.ArtistName)
Expand Down

0 comments on commit b974e13

Please sign in to comment.