diff options
| author | Serguey Parkhomovsky <xindigo@gmail.com> | 2023-08-22 20:27:49 -0700 |
|---|---|---|
| committer | Serguey Parkhomovsky <xindigo@gmail.com> | 2023-08-22 20:27:49 -0700 |
| commit | 5f5341b7962895869e8800a7f1c7e38d019b9735 (patch) | |
| tree | 6aefda545e8d0fc299e4c742c248919d53e290a1 | |
init
| -rw-r--r-- | .gitignore | 21 | ||||
| -rw-r--r-- | go.mod | 14 | ||||
| -rw-r--r-- | go.sum | 17 | ||||
| -rw-r--r-- | main.go | 113 |
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 @@ -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 +) @@ -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= @@ -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!") +} |
