@@ 1,200 @@
+package main
+
+import (
+ "log"
+ "fmt"
+ "flag"
+ "encoding/xml"
+ "io/ioutil"
+ "io"
+ "net/http"
+ "net/url"
+ "path/filepath"
+ "strings"
+ "os"
+ "bufio"
+ "github.com/schollz/progressbar/v3"
+)
+
+type Item struct {
+ Text string `xml:",chardata"`
+ Title string `xml:"title"`
+ Description string `xml:"description"`
+ Link string `xml:"link"`
+ Guid struct {
+ Text string `xml:",chardata"`
+ IsPermaLink string `xml:"isPermaLink,attr"`
+ } `xml:"guid"`
+ Category string `xml:"category"`
+ Creator string `xml:"creator"`
+ PubDate string `xml:"pubDate"`
+ Enclosure struct {
+ Text string `xml:",chardata"`
+ URL string `xml:"url,attr"`
+ Length string `xml:"length,attr"`
+ Type string `xml:"type,attr"`
+ } `xml:"enclosure"`
+ Duration string `xml:"duration"`
+ WebsiteUrl string `xml:"websiteUrl"`
+}
+
+type Rss struct {
+ XMLName xml.Name `xml:"rss"`
+ Text string `xml:",chardata"`
+ Dc string `xml:"dc,attr"`
+ Content string `xml:"content,attr"`
+ Atom string `xml:"atom,attr"`
+ Version string `xml:"version,attr"`
+ Channel struct {
+ Text string `xml:",chardata"`
+ Title string `xml:"title"`
+ Description string `xml:"description"`
+ Link struct {
+ Text string `xml:",chardata"`
+ Href string `xml:"href,attr"`
+ Rel string `xml:"rel,attr"`
+ Type string `xml:"type,attr"`
+ } `xml:"link"`
+ Generator string `xml:"generator"`
+ LastBuildDate string `xml:"lastBuildDate"`
+ Ttl string `xml:"ttl"`
+ Item []*Item `xml:"item"`
+ } `xml:"channel"`
+}
+
+func openXMLFromURL(URL string) (*Rss, error) {
+ resp, err := http.Get(URL)
+ if err != nil {
+ return &Rss{}, fmt.Errorf("GET error: %v", err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ return &Rss{}, fmt.Errorf("HTTP-Status error: %v", err)
+ }
+ xmlBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return &Rss{}, fmt.Errorf("Read body: %v", err)
+ }
+ var result *Rss
+ xml.Unmarshal(xmlBytes, &result)
+ return result, nil
+}
+
+func dirExists(dir string) bool {
+ _, err := os.Stat(dir)
+ return !os.IsNotExist(err)
+}
+
+func mkdir(dir string) error {
+ var err error
+ if !dirExists(dir) {
+ err := os.MkdirAll(dir, 0750)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ return err
+}
+
+func getItemDir(dir string, item *Item) string {
+ translate := map[string]string{}
+ translate["%t"] = item.Title
+ translate["%c"] = item.Category
+ translate["%C"] = item.Creator
+ translate["%D"] = item.PubDate
+ translate["%G"] = item.Guid.Text
+ translate["%T"] = item.Text
+ translate["%e"] = filepath.Ext(item.Link)
+ for k, v := range translate {
+ dir = strings.Replace(dir, k, v, -1)
+ }
+ return dir
+}
+
+func itemExists(item *Item, directory string) (bool) {
+ readFile, err := os.Open(filepath.Join(directory,".guid"))
+ if os.IsNotExist(err) {
+ return false
+ }
+ if err != nil {
+ log.Println(err)
+ }
+ fileScanner := bufio.NewScanner(readFile)
+ fileScanner.Split(bufio.ScanLines)
+ for fileScanner.Scan() {
+ if fileScanner.Text() == item.Guid.Text {
+ return true
+ }
+ }
+ readFile.Close()
+ return false
+}
+
+func processItem(item *Item, directory string) {
+ itemDirFull := getItemDir(directory, item)
+ itemDirectory := filepath.Dir(itemDirFull)
+ itemFile := filepath.Base(itemDirFull)
+
+ err := mkdir(itemDirectory)
+ if err != nil {
+ fmt.Println(err)
+ }
+ if itemExists(item, itemDirectory) {
+ fmt.Printf("Vorhanden, überspringen: %s, %s, %s\n", item.Creator, item. Category, item.Title)
+ return
+ }
+ //download
+ req, _ := http.NewRequest("GET", item.Link, nil)
+ resp, _ := http.DefaultClient.Do(req)
+ defer resp.Body.Close()
+
+ f, _ := os.OpenFile(filepath.Join(itemDirectory, itemFile), os.O_CREATE|os.O_WRONLY, 0644)
+ defer f.Close()
+ fmt.Printf("Downloading %s", item.Title)
+ bar := progressbar.DefaultBytes(resp.ContentLength, fmt.Sprintf("%s, %s, %s", item.Creator, item. Category, item.Title),)
+ io.Copy(io.MultiWriter(f, bar), resp.Body)
+
+ //remember guid
+ f, e := os.OpenFile(filepath.Join(itemDirectory,".guid"), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
+ if e != nil {
+ panic(e)
+ }
+ defer f.Close()
+ if _, err = f.WriteString(item.Guid.Text+"\n"); err != nil {
+ panic(err)
+ }
+
+ //DONE
+}
+
+func processFeed(adress, outputDirectory string) {
+ feed, err := openXMLFromURL(adress)
+ if err != nil {
+ fmt.Println(err)
+ }
+ for _, item := range feed.Channel.Item {
+ processItem(item, outputDirectory)
+ }
+}
+
+func getSearchQuery(searchFlag *string) string {
+ ret := "https://mediathekviewweb.de/feed?query="
+ ret += url.QueryEscape(*searchFlag)
+ return ret
+}
+
+func main() {
+
+ searchFlag := flag.String("s","","!Sender #Thema +Titel *Beschreibung")
+ feedFlag := flag.String("f","","URI to feed")
+ directoryFlag := flag.String("d","./%C/%c/%t%e","directory to safe content")
+ flag.Parse()
+ if len(*feedFlag) > 0 {
+ processFeed(*feedFlag, *directoryFlag)
+ } else if len(*searchFlag) > 0 {
+ processFeed(getSearchQuery(searchFlag), *directoryFlag)
+ } else {
+ fmt.Println("kein Feed übergeben")
+ }
+
+}