summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerguey Parkhomovsky <xindigo@gmail.com>2023-08-22 20:27:49 -0700
committerSerguey Parkhomovsky <xindigo@gmail.com>2023-08-22 20:27:49 -0700
commit5f5341b7962895869e8800a7f1c7e38d019b9735 (patch)
tree6aefda545e8d0fc299e4c742c248919d53e290a1
init
-rw-r--r--.gitignore21
-rw-r--r--go.mod14
-rw-r--r--go.sum17
-rw-r--r--main.go113
4 files changed, 165 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3b735ec
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..8d5e141
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,14 @@
+module github.com/sparkhom/wbdl
+
+go 1.17
+
+require (
+ github.com/PuerkitoBio/goquery v1.7.1
+ github.com/bogem/id3v2 v1.2.0
+)
+
+require (
+ github.com/andybalholm/cascadia v1.2.0 // indirect
+ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect
+ golang.org/x/text v0.3.6 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..cd10c91
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,17 @@
+github.com/PuerkitoBio/goquery v1.7.1 h1:oE+T06D+1T7LNrn91B4aERsRIeCLJ/oPSa6xB9FPnz4=
+github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY=
+github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
+github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
+github.com/bogem/id3v2 v1.2.0 h1:hKDF+F1gOgQ5r1QmBCEZUk4MveJbKxCeIDSBU7CQ4oI=
+github.com/bogem/id3v2 v1.2.0/go.mod h1:t78PK5AQ56Q47kizpYiV6gtjj3jfxlz87oFpty8DYs8=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210917221730-978cfadd31cf h1:R150MpwJIv1MpS0N/pc+NhTM8ajzvlmxlY5OYsrevXQ=
+golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..7459652
--- /dev/null
+++ b/main.go
@@ -0,0 +1,113 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "path"
+ "regexp"
+ "strconv"
+
+ "github.com/PuerkitoBio/goquery"
+ "github.com/bogem/id3v2"
+)
+
+func main() {
+ if len(os.Args) != 4 {
+ fmt.Fprintf(os.Stderr, "usage: %v <artist> <year> /path/to/download\n", os.Args[0])
+ os.Exit(1)
+ }
+ artist, year, dir := os.Args[1], os.Args[2], os.Args[3]
+ fmt.Printf("[+] Retrieving tracks for %v (%v)\n", artist, year)
+ fmt.Printf("[+] Saving to %v\n", dir)
+
+ // Get weeklybeats HTML
+ url := fmt.Sprintf("https://weeklybeats.com/%v?y=%v", artist, year)
+ resp, err := http.Get(url)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != 200 {
+ log.Fatalf("status code error: %d %s", resp.StatusCode, resp.Status)
+ }
+
+ doc, err := goquery.NewDocumentFromReader(resp.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ type track struct {
+ title string
+ fileName string
+ url string
+ num int
+ }
+
+ var tracks []track
+
+ // Find the tracks
+ urlRegex, err := regexp.Compile(`(https:\/\/weeklybeats\.s3\.amazonaws\.com\/music\/\d{4}\/(.+_weeklybeats-\d{4}_(\d+)_.+.mp3))`)
+ if err != nil {
+ log.Fatal(err)
+ }
+ doc.Find("h3.hn").Each(func(i int, s *goquery.Selection) {
+ track := track{}
+ // For each item, get the name, url, and number.
+ js, exists := s.Find("div").Attr("onclick")
+ if !exists {
+ log.Fatal("error: url does not exist for a track")
+ }
+ submatches := urlRegex.FindStringSubmatch(js)
+ track.url = submatches[1]
+ track.fileName = submatches[2]
+ num, err := strconv.Atoi(submatches[3])
+ if err != nil {
+ log.Fatal(err)
+ }
+ track.num = num
+ track.title = s.Find("a").Text()
+ tracks = append(tracks, track)
+ })
+
+ // Now, download the tracks.
+ for track := range tracks {
+ fmt.Printf("[+] Downloading %v\n", tracks[track].title)
+ resp, err := http.Get(tracks[track].url)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer resp.Body.Close()
+
+ p := path.Join(dir, tracks[track].fileName)
+ out, err := os.Create(p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer out.Close()
+ _, err = io.Copy(out, resp.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("[+] Tagging %v\n", tracks[track].title)
+ tagFile, err := id3v2.Open(p, id3v2.Options{})
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer tagFile.Close()
+
+ tagFile.SetAlbum(fmt.Sprintf("Weeklybeats %v", year))
+ tagFile.SetArtist(artist)
+ tagFile.SetTitle(tracks[track].title)
+ tagFile.AddTextFrame("TRCK", tagFile.DefaultEncoding(), fmt.Sprintf("%d", tracks[track].num))
+ err = tagFile.Save()
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ fmt.Println("[+] Done!")
+}