Multiple:
- Added LICENSE - Updated README - Added progress indicator - File downloads as .tmp file before being completed
This commit is contained in:
parent
a09cd4c6f8
commit
6850cad08d
|
@ -0,0 +1,19 @@
|
|||
Copyright <2021> <Donnie Corbitt>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
11
README.md
11
README.md
|
@ -2,15 +2,12 @@
|
|||
This is a download manager that I'm making entirely in go.
|
||||
|
||||
# Building
|
||||
run the following command to run without making an executable:
|
||||
|
||||
`go run dmig.go`
|
||||
|
||||
or to build an executable...
|
||||
`go mod init dmig`
|
||||
|
||||
`go build dmig.go`
|
||||
|
||||
|
||||
# TODO
|
||||
- [x] Ask for url of file to download instead of needing to edit source
|
||||
- [ ] Add progress bar/percentage
|
||||
- [x] Add progress bar/percentage
|
||||
- [ ] Have automatic file naming
|
||||
- [ ] Assume the url is https by default
|
58
dmig.go
58
dmig.go
|
@ -16,8 +16,35 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
|
||||
// WriteCounter counts the number of bytes written to it. It implements to the
|
||||
// io.Writer interface and we pass this into io.TeeReader() which will report
|
||||
// progress on each write cycle.
|
||||
type WriteCounter struct {
|
||||
Total uint64
|
||||
}
|
||||
|
||||
func (wc *WriteCounter) Write(p []byte) (int, error) {
|
||||
n := len(p)
|
||||
wc.Total += uint64(n)
|
||||
wc.PrintProgress()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (wc WriteCounter) PrintProgress() {
|
||||
// Clear the line by using a character return to go back to the start and
|
||||
// remove the remaining characters by filling it with spaces
|
||||
fmt.Printf("\r%s", strings.Repeat(" ", 35))
|
||||
|
||||
// Return again and print current status of download
|
||||
// Humanize package used so the amount is in a human readable way (ex: 100MB)
|
||||
fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total))
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Asks the user what the url to the file is.
|
||||
// Input will be below the following text.
|
||||
|
@ -37,13 +64,21 @@ func main() {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println("Downloaded: " + fileUrl)
|
||||
fmt.Println("Downloaded: " + fileName)
|
||||
}
|
||||
|
||||
// DownloadedFile will download a url to a local file. It's efficient because it
|
||||
// write as it downloads and not load the whole file into memory
|
||||
func DownloadFile(filepath string, url string) error {
|
||||
|
||||
// Create the file, but give it a tmp file extension, this means we won't
|
||||
// overwrite a file unless it's downloaded, the .tmp will be removed when
|
||||
// download completes.
|
||||
out, err := os.Create(filepath + ".tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the data
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
|
@ -51,14 +86,21 @@ func DownloadFile(filepath string, url string) error {
|
|||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Create the file
|
||||
out, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
// Create progress report and pass it to be used alongside the writer
|
||||
counter := &WriteCounter{}
|
||||
if _, err = io.Copy(out, io.TeeReader(resp.Body, counter)); err != nil {
|
||||
out.Close()
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
// Write the body to file
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
return err
|
||||
// The progress use the same line so print a new line once it's done.
|
||||
fmt.Print("\n")
|
||||
|
||||
// Close the file without defer so it can happen before Rename()
|
||||
out.Close()
|
||||
|
||||
if err = os.Rename(filepath+".tmp", filepath); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue