106 lines
2.4 KiB
Go
106 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mmcdole/gofeed"
|
|
)
|
|
|
|
const durationPattern = `^([0-9]+:)?([0-9]+:)?([0-9]+(\.[0-9]+)?)$`
|
|
|
|
var durationRegexp = regexp.MustCompile(durationPattern)
|
|
|
|
func main() {
|
|
playlist, err := feed2m3u("https://feeds.soundcloud.com/users/soundcloud:users:520257816/sounds.rss")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
fmt.Println(playlist)
|
|
}
|
|
|
|
func feed2m3u(feedURL string) (string, error) {
|
|
parser := gofeed.NewParser()
|
|
feed, err := parser.ParseURL(feedURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
defaultAuthor := "No Author"
|
|
if feed.Author != nil && feed.Author.Name != "" {
|
|
defaultAuthor = feed.Author.Name
|
|
}
|
|
|
|
defaultTitle := "No Title"
|
|
if feed.Title != "" {
|
|
defaultTitle = feed.Title
|
|
}
|
|
|
|
playlistBuffer := bytes.NewBuffer(nil)
|
|
|
|
fmt.Fprintln(playlistBuffer, "#EXTM3U")
|
|
|
|
for _, item := range feed.Items {
|
|
duration := -1
|
|
if item.ITunesExt != nil && item.ITunesExt.Duration != "" {
|
|
duration, err = normalizeDuration(item.ITunesExt.Duration)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
title := defaultTitle
|
|
if item.Title != "" {
|
|
title = item.Title
|
|
}
|
|
|
|
author := defaultAuthor
|
|
if item.Author != nil && item.Author.Name != "" {
|
|
author = item.Author.Name
|
|
}
|
|
|
|
for _, enclosure := range item.Enclosures {
|
|
if strings.HasPrefix(strings.ToLower(enclosure.Type), "audio/") {
|
|
fmt.Fprintf(playlistBuffer, "\n#EXTINF:%d, %s - %s\n%s\n", duration, title, author, enclosure.URL)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return playlistBuffer.String(), nil
|
|
}
|
|
|
|
func normalizeDuration(durationString string) (int, error) {
|
|
durationString = strings.ReplaceAll(durationString, " ", "")
|
|
|
|
ok := durationRegexp.MatchString(durationString)
|
|
if ok {
|
|
durationComponents := strings.Split(durationString, ":")
|
|
var total float64 = 0
|
|
for i, value := range durationComponents {
|
|
intValue, err := strconv.ParseFloat(value, 64)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
total += intValue * math.Pow(60, float64(len(durationComponents)-i-1))
|
|
}
|
|
|
|
return int(total), nil
|
|
}
|
|
|
|
durationString = strings.ReplaceAll(durationString, "min", "m")
|
|
durationString = strings.ReplaceAll(durationString, "sec", "s")
|
|
if duration, err := time.ParseDuration(durationString); err == nil {
|
|
return int(duration.Seconds()), nil
|
|
}
|
|
|
|
return 0, errors.New("NormalizeDuration: duration didn't match the duration pattern")
|
|
}
|