2021-10-24 21:48:36 +02:00
|
|
|
//nolint:gochecknoglobals
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
"regexp"
|
|
|
|
"runtime"
|
|
|
|
"strconv"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/gocolly/colly/v2"
|
2021-10-25 09:21:00 +02:00
|
|
|
id3 "github.com/mikkyang/id3-go"
|
2021-10-24 21:48:36 +02:00
|
|
|
"go.xsfx.dev/workgroups"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-10-25 09:21:00 +02:00
|
|
|
URL = "https://susallefolgen.netlify.app/"
|
|
|
|
Artist = "Sanft & Sorgfältig"
|
2021-10-24 21:48:36 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type Episode struct {
|
|
|
|
Title string
|
|
|
|
Number int
|
|
|
|
Date time.Time
|
|
|
|
URL string
|
|
|
|
file string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Episodes struct {
|
|
|
|
sync.Mutex
|
|
|
|
Episodes []Episode
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *Episode) ParseTitle(title string) error {
|
|
|
|
re := regexp.MustCompile(`^#(?P<episode>\d+)\s(?P<title>.+)`)
|
|
|
|
match := re.FindStringSubmatch(title)
|
|
|
|
|
|
|
|
number, err := strconv.Atoi(match[1])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not convert number string to int: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
e.Number = number
|
|
|
|
|
|
|
|
e.Title = match[2]
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var episodes Episodes
|
|
|
|
|
|
|
|
func (e *Episode) Download() error {
|
|
|
|
log.Printf("downloading: %d - %s", e.Number, e.Title)
|
|
|
|
|
|
|
|
resp, err := http.Get(e.URL)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not download: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
2021-10-25 09:21:00 +02:00
|
|
|
e.file = fmt.Sprintf("%d.mp3", e.Number)
|
|
|
|
|
|
|
|
f, err := os.Create(e.file)
|
2021-10-24 21:48:36 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not create file: %w", err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
if _, err := io.Copy(f, resp.Body); err != nil {
|
|
|
|
return fmt.Errorf("could not copy body to file: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-10-25 09:21:00 +02:00
|
|
|
func (e *Episode) Tag() error {
|
|
|
|
f, err := id3.Open(e.file)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not open file: %w", err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
title := fmt.Sprintf("#%03d %s", e.Number, e.Title)
|
|
|
|
|
|
|
|
f.SetArtist(Artist)
|
|
|
|
f.SetAlbum(title)
|
|
|
|
f.SetTitle(title)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-10-24 21:48:36 +02:00
|
|
|
//nolint:funlen
|
|
|
|
func main() {
|
|
|
|
c := colly.NewCollector()
|
|
|
|
|
|
|
|
c.OnHTML("body div.container div", func(e *colly.HTMLElement) {
|
|
|
|
episode := Episode{}
|
|
|
|
|
|
|
|
e.ForEach("strong", func(_ int, el *colly.HTMLElement) {
|
|
|
|
if err := episode.ParseTitle(el.Text); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
e.ForEach("table.u-full-width tbody tr td em", func(_ int, el *colly.HTMLElement) {
|
|
|
|
t, err := time.Parse("Mon, 02 Jan 2006", el.Text)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
episode.Date = t
|
|
|
|
})
|
|
|
|
|
|
|
|
e.ForEach("table.u-full-width tbody tr td a", func(_ int, el *colly.HTMLElement) {
|
|
|
|
episode.URL = el.Attr("href")
|
|
|
|
})
|
|
|
|
|
|
|
|
episodes.Lock()
|
|
|
|
episodes.Episodes = append(episodes.Episodes, episode)
|
|
|
|
episodes.Unlock()
|
|
|
|
})
|
|
|
|
|
|
|
|
c.Visit(URL)
|
|
|
|
|
|
|
|
// j, err := json.MarshalIndent(episodes, "", " ")
|
|
|
|
// if err != nil {
|
|
|
|
// log.Fatal(err)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// fmt.Print(string(j))
|
|
|
|
|
|
|
|
d, ctx := workgroups.NewDispatcher(
|
|
|
|
context.Background(),
|
|
|
|
runtime.GOMAXPROCS(0),
|
2021-10-25 09:21:00 +02:00
|
|
|
len(episodes.Episodes[:1]),
|
2021-10-24 21:48:36 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
d.Start()
|
|
|
|
|
2021-10-25 09:21:00 +02:00
|
|
|
for _, ep := range episodes.Episodes[:1] {
|
2021-10-24 21:48:36 +02:00
|
|
|
ep := ep
|
|
|
|
|
|
|
|
d.Append(workgroups.NewJob(ctx, func(ctx context.Context) error {
|
|
|
|
select {
|
|
|
|
default:
|
|
|
|
case <-ctx.Done():
|
|
|
|
return fmt.Errorf("got error from context: %w", ctx.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ep.Download(); err != nil {
|
|
|
|
return fmt.Errorf("could not download: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-10-25 09:21:00 +02:00
|
|
|
if err := ep.Tag(); err != nil {
|
|
|
|
return fmt.Errorf("could not tag: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-10-24 21:48:36 +02:00
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
d.Close()
|
|
|
|
|
|
|
|
if err := d.Wait(); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|