-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
feedload.go
125 lines (103 loc) · 2.72 KB
/
feedload.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"fmt"
"github.com/asaskevich/govalidator"
"github.com/mmcdole/gofeed"
"github.com/vbauerster/mpb"
"github.com/vbauerster/mpb/decor"
"io"
"log"
"net/http"
"os"
"strings"
)
const WORKERS = 8
func main() {
if len(os.Args) <= 1 {
log.Fatal("No target rss url specified")
}
rssUrl := os.Args[1]
if !govalidator.IsURL(rssUrl) {
log.Fatal("Your argument is no valid url")
}
download(rssUrl)
fmt.Println("Finished")
}
func download(url string) {
progress := mpb.New()
//start workers
jobs := make(chan gofeed.Item, 2)
done := make(chan struct{}, 2)
for w := 0; w < WORKERS; w++ {
go worker(jobs, done, progress)
}
//read rss
feed, err := gofeed.NewParser().ParseURL(url)
if err != nil {
log.Fatal("Cannot parse feed source", err)
}
//count all episodes to make an progress bar
totalEpisodes := len(feed.Items)
go progressCounter(progress, totalEpisodes, done)
//submit all rss entries to the workers
fmt.Println("Downloading all episodes from", feed.Title)
for _, item := range feed.Items {
jobs <- *item
}
//Wait and clean up
close(jobs)
close(done)
progress.Stop()
}
func progressCounter(progress *mpb.Progress, totalEpisodes int, done <-chan struct{}) {
bar := createBar(progress, "All", 0, int64(totalEpisodes))
for range done {
bar.Incr(1)
}
}
func worker(jobs <-chan gofeed.Item, done chan<- struct{}, progress *mpb.Progress) {
for item := range jobs {
enclosures := item.Enclosures
downloadSource := enclosures[0].URL
fileExt := extractFileExt(downloadSource)
downloadFile(item.Title, fileExt, downloadSource, progress)
done <- struct{}{}
}
}
func extractFileExt(downloadSource string) string {
//extract the file extension from the url
split := strings.Split(downloadSource, ".")
return split[len(split)-1]
}
func downloadFile(title string, ext string, url string, progress *mpb.Progress) {
//create output file
out, err := os.Create(title + "." + ext)
defer out.Close()
if err != nil {
//cancel processing of this file
log.Println("Failed to create file", err)
return
}
//connect with http
resp, err := http.Get(url)
defer resp.Body.Close()
//add progress with the maximum file size
bar := createBar(progress, title, decor.Unit_KiB, resp.ContentLength)
defer progress.RemoveBar(bar)
//write contents to disk
_, err = io.Copy(out, bar.ProxyReader(resp.Body))
if err != nil {
log.Println("Failed to download file", err)
}
}
func createBar(progress *mpb.Progress, name string, counterUnit decor.Units, total int64) *mpb.Bar {
return progress.AddBar(total,
mpb.PrependDecorators(
decor.Name(name, 0, decor.DwidthSync),
decor.Counters("%3s/%3s", counterUnit, 18, 0),
),
mpb.AppendDecorators(
decor.ETA(3, 0),
decor.Percentage(5, 0),
))
}