Work-in-progress. This repository contains some scripts to prepare SD card images for the raspberry Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

116 lines
2.1 KiB

2 years ago
  1. package main
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "log"
  7. "net/http"
  8. "os"
  9. "path"
  10. "regexp"
  11. "sort"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "github.com/gocolly/colly"
  16. "github.com/machinebox/progress"
  17. )
  18. func list() {
  19. c := colly.NewCollector(
  20. colly.AllowedDomains("downloads.raspberrypi.org"),
  21. colly.UserAgent("github.com/klingtnet/raspi-toolbox"),
  22. colly.Async(true),
  23. )
  24. c.Limit(&colly.LimitRule{Parallelism: 4})
  25. urls := []string{}
  26. imgMatcher := regexp.MustCompile(".*raspbian-stretch-lite.*\\.zip$")
  27. c.OnHTML("a[href]", func(e *colly.HTMLElement) {
  28. link := e.Attr("href")
  29. if strings.HasPrefix(link, "raspbian_lite") {
  30. c.Visit(e.Request.AbsoluteURL(link))
  31. return
  32. }
  33. if imgMatcher.Match([]byte(link)) {
  34. urls = append(urls, e.Request.AbsoluteURL(link))
  35. }
  36. })
  37. c.Visit("https://downloads.raspberrypi.org/raspbian_lite/images/")
  38. c.Wait()
  39. sort.Strings(urls)
  40. for _, u := range urls {
  41. fmt.Println(u)
  42. }
  43. }
  44. func download(u string) error {
  45. filename := path.Base(u)
  46. fmt.Printf("writing into %q\n", filename)
  47. f, err := os.Create(filename)
  48. if err != nil {
  49. return err
  50. }
  51. defer f.Close()
  52. resp, err := http.Get(u)
  53. if err != nil {
  54. return err
  55. }
  56. defer resp.Body.Close()
  57. if resp.StatusCode != http.StatusOK {
  58. return fmt.Errorf("expected HTTP 200 OK but was %d", resp.StatusCode)
  59. }
  60. size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
  61. if err != nil {
  62. return err
  63. }
  64. pr := progress.NewReader(resp.Body)
  65. go func() {
  66. progressChan := progress.NewTicker(context.Background(), pr, int64(size), 3*time.Second)
  67. for p := range progressChan {
  68. fmt.Printf("\r%.2f%%", p.Percent())
  69. }
  70. }()
  71. _, err = io.Copy(f, pr)
  72. fmt.Println("\r100.0%")
  73. return err
  74. }
  75. func usage() {
  76. fmt.Printf(`%s [list|usage|help|<url>]
  77. usage|help:
  78. Prints this message
  79. list:
  80. Prints all available images
  81. <url>:
  82. Downloads the image under <url>
  83. `, os.Args[0])
  84. }
  85. func main() {
  86. if len(os.Args) <= 1 {
  87. usage()
  88. os.Exit(1)
  89. }
  90. arg := os.Args[1]
  91. switch arg {
  92. case "usage":
  93. fallthrough
  94. case "help":
  95. usage()
  96. return
  97. case "list":
  98. list()
  99. default:
  100. if err := download(os.Args[1]); err != nil {
  101. log.Fatalln(err)
  102. }
  103. }
  104. }