-
Notifications
You must be signed in to change notification settings - Fork 0
/
xml.go
152 lines (133 loc) · 4.17 KB
/
xml.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package miniocast
import (
"bytes"
"context"
"encoding/binary"
"encoding/xml"
"io"
"log"
"strconv"
"strings"
"time"
"github.com/eduncan911/podcast"
"github.com/minio/minio-go/v7"
)
// RSS はfeed.rss のデータ全体。
type RSS struct {
XMLName xml.Name `xml:"rss"`
Channel podcast.Podcast `xml:"channel"`
}
// UpdateRSS は、フィードを作成あるいは更新する
func (pref *PodcastPref) UpdateRSS(infos FileInfos, ct *minio.Client) {
rss := pref.newRSS()
items, err := pref.itemsFromInfo(infos)
if err != nil {
log.Printf("info: %s の新規アイテムの作成に失敗しました:%s", pref.Folder, err)
return
}
for _, item := range items {
_, _ = rss.AddItem(item)
}
now := time.Now()
rss.AddPubDate(&now)
rss.AddLastBuildDate(&now)
// log.Printf("info: %s", rss)
if err := pref.uploadRSS(ct, rss); err != nil {
log.Printf("info: feed.rssのアップロードに失敗しました:%s", err)
}
}
// newRSS は、Podcast構造体を初期化する
func (pref *PodcastPref) newRSS() (rss *podcast.Podcast) {
now := time.Now()
rssr := podcast.New(pref.Title, pref.Link+"/index.html", pref.Description, &now, &now)
rssr.AddAtomLink(pref.Link + "/feed.rss")
if pref.Subtitle != "" {
rssr.AddSubTitle(pref.Subtitle)
}
rssr.AddAuthor(pref.Author, pref.Email)
rssr.AddCategory("Personal Journals", nil)
rssr.AddImage(pref.Link + "/image.jpg")
rssr.Language = "ja"
rss = &rssr
return
}
// fetchExistingIndexes は、既存のアイテムのインデックスを返す
func (pref *PodcastPref) fetchExistingIndexes(ct *minio.Client) (olds Indexes, err error) {
ctx := context.Background()
reader, err := ct.GetObject(ctx, pref.Bucket, pref.Folder+"/feed.rss", minio.GetObjectOptions{})
if err != nil {
log.Printf("info: %s のRSSファイルが取得できません:%s", pref.Folder, err)
return
}
defer reader.Close()
var items []*podcast.Item
decoder := xml.NewDecoder(reader)
for {
token, err := decoder.Token()
if err == io.EOF {
break
}
if err != nil {
log.Printf("info: %s のxmlのデコードに失敗しました:%s", pref.Folder, err)
return Indexes{}, err
}
switch se := token.(type) {
case xml.StartElement:
if se.Name.Local == "item" {
var item podcast.Item
decoder.DecodeElement(&item, &se)
items = append(items, &item)
}
}
}
for _, item := range items {
idx := Index{}
idx.FileLink = item.Link
idx.Updated = item.PubDateFormatted
olds = append(olds, idx)
}
return
}
// itemsFromInfo は、音声ファイルのObjectInfoをもとにRSSアイテムの構造体を生成する
func (pref *PodcastPref) itemsFromInfo(fInfos FileInfos) (items []podcast.Item, err error) {
lastID := len(fInfos)
if lastID == 0 {
return
}
for i, info := range fInfos {
item := podcast.Item{}
fn := strings.TrimLeft(info.Key, pref.Folder+"/")
id, title, sub := getDetailsFromName(fn)
idst := ""
// Descriptionは空にできない。
item.Description = " "
item.ISubtitle = sub
if id != 0 {
idst = " 第" + strconv.Itoa(id) + "回"
} else if pref.Serial > 0 {
idst = " 第" + strconv.Itoa(lastID+pref.Serial-1-i) + "回"
}
item.Title = title + idst
url := pref.Link + strings.TrimLeft(info.Key, pref.Folder)
tp := getType(info)
item.AddEnclosure(url, tp, info.Size)
upd := info.LastModified
// 「for rangeのrangeの返り値には同じ参照先が使用されている。」
// https://qiita.com/RunEagler/items/008e2b304f27b7fb168a
// だから、&info.LastModifiedを引数に指定しても、それは最終的に全て同じ値になってしまう
item.AddPubDate(&upd)
items = append(items, item)
}
return
}
// uploadRSS は、クラウドストレージにfeed.rssをアップロードする
func (pref *PodcastPref) uploadRSS(ct *minio.Client, rss *podcast.Podcast) (err error) {
ctx := context.Background()
bts := rss.Bytes()
reader := bytes.NewReader(bts)
_, err = ct.PutObject(ctx, pref.Bucket, pref.Folder+"/feed.rss", reader, int64(binary.Size(bts)), minio.PutObjectOptions{ContentType: "application/rss+xml"})
if err != nil {
log.Printf("alert: %s のrssファイルのアップロードに失敗しました:%s", pref.Folder, err)
}
return
}