Skip to content

Commit acd6469

Browse files
committed
add support for value time splits
1 parent 1d950db commit acd6469

File tree

4 files changed

+77
-5
lines changed

4 files changed

+77
-5
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ module github.com/rssblue/types
33
go 1.18
44

55
require github.com/google/go-cmp v0.5.9
6+
7+
require github.com/google/uuid v1.3.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
22
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3+
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
4+
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

namespace_podcast.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package types
33
import (
44
"encoding/xml"
55
"fmt"
6+
"math"
67
"strconv"
78
"strings"
89
"time"
10+
11+
"github.com/google/uuid"
912
)
1013

1114
// NamespacePodcast is the Podcasting 2.0 namespace.
@@ -36,11 +39,12 @@ type PodcastChapters struct {
3639
// PodcastValue enables to describe Value 4 Value payments. Read more at
3740
// https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#value
3841
type PodcastValue struct {
39-
XMLName xml.Name `xml:"podcast:value"`
40-
Type string `xml:"type,attr"`
41-
Method string `xml:"method,attr"`
42-
Suggested *float64 `xml:"suggested,attr,omitempty"`
43-
Recipients []PodcastValueRecipient
42+
XMLName xml.Name `xml:"podcast:value"`
43+
Type string `xml:"type,attr"`
44+
Method string `xml:"method,attr"`
45+
Suggested *float64 `xml:"suggested,attr,omitempty"`
46+
Recipients []PodcastValueRecipient
47+
ValueTimeSplits []PodcastValueTimeSplit
4448
}
4549

4650
// PodcastValueRecipient describes the recipient of Value 4 Value payments.
@@ -57,6 +61,29 @@ type PodcastValueRecipient struct {
5761
Fee *bool `xml:"bool,attr"`
5862
}
5963

64+
// PodcastValueTimeSplit describes value splits that are valid for a certain period of time
65+
// Read more at
66+
// https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#value-time-split
67+
type PodcastValueTimeSplit struct {
68+
XMLName xml.Name `xml:"podcast:valueTimeSplit"`
69+
StartTime DurationInteger `xml:"startTime,attr"`
70+
Duration DurationInteger `xml:"duration,attr"`
71+
RemoteStartTime *DurationInteger `xml:"remoteStartTime,attr,omitempty"`
72+
RemotePercentage *uint `xml:"remotePercentage,attr,omitempty"`
73+
Recipients []PodcastValueRecipient
74+
RemoteItem PodcastRemoteItem
75+
}
76+
77+
// PodcastRemoteItem provides a way to "point" to another feed or item in it.
78+
// Read more at
79+
// https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#remote-item
80+
type PodcastRemoteItem struct {
81+
XMLName xml.Name `xml:"podcast:remoteItem"`
82+
ItemGUID *string `xml:"itemGuid,attr"`
83+
FeedGUID uuid.UUID `xml:"feedGuid,attr"`
84+
Medium *PodcastMedium `xml:"medium,attr"`
85+
}
86+
6087
// PodcastLocked tells podcast hosting platforms whether they are allowed to import
6188
// the feed. Read more at
6289
// https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#locked
@@ -170,6 +197,17 @@ func (duration Duration) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
170197
return xml.Attr{Name: xml.Name{Local: name.Local}, Value: s}, nil
171198
}
172199

200+
// DurationInteger denotes timestamps and durations during a podcast episode, but which are converted to integer seconds.
201+
type DurationInteger time.Duration
202+
203+
func (duration DurationInteger) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
204+
seconds := time.Duration(duration).Seconds()
205+
seconds = math.Round(seconds)
206+
s := strconv.Itoa(int(seconds))
207+
208+
return xml.Attr{Name: xml.Name{Local: name.Local}, Value: s}, nil
209+
}
210+
173211
// PodcastPerson specifies a person of interest to the podcast. Read more at
174212
// https://github.com/Podcastindex-org/podcast-namespace/blob/main/docs/1.0.md#person
175213
type PodcastPerson struct {

types_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"github.com/google/go-cmp/cmp"
10+
"github.com/google/uuid"
1011
"github.com/rssblue/types"
1112
)
1213

@@ -91,6 +92,29 @@ func TestMarshal(t *testing.T) {
9192
Split: 10,
9293
},
9394
},
95+
ValueTimeSplits: []types.PodcastValueTimeSplit{
96+
{
97+
StartTime: types.DurationInteger(60 * time.Second),
98+
Duration: types.DurationInteger(237 * time.Second),
99+
RemoteItem: types.PodcastRemoteItem{
100+
ItemGUID: pointer("https://podcastindex.org/podcast/4148683#1"),
101+
FeedGUID: uuid.MustParse("a94f5cc9-8c58-55fc-91fe-a324087a655b"),
102+
Medium: pointer(types.PodcastMediumMusic),
103+
},
104+
RemotePercentage: pointer[uint](95),
105+
},
106+
{
107+
StartTime: types.DurationInteger(330 * time.Second),
108+
Duration: types.DurationInteger(53 * time.Second),
109+
RemoteItem: types.PodcastRemoteItem{
110+
ItemGUID: pointer("https://podcastindex.org/podcast/4148683#3"),
111+
FeedGUID: uuid.MustParse("a94f5cc9-8c58-55fc-91fe-a324087a655b"),
112+
Medium: pointer(types.PodcastMediumMusic),
113+
},
114+
RemoteStartTime: pointer(types.DurationInteger(174 * time.Second)),
115+
RemotePercentage: pointer[uint](95),
116+
},
117+
},
94118
},
95119
PodcastGUID: pointer(types.PodcastGUID("cda647ce-56b8-5d7c-9448-ba1993ab46b7")),
96120
PodcastMedium: &types.PodcastMediumPodcast,
@@ -375,6 +399,12 @@ func TestMarshal(t *testing.T) {
375399
<podcast:valueRecipient name="Co-Host #1" type="node" address="02d5c1bf8b940dc9cadca86d1b0a3c37fbe39cee4c7e839e33bef9174531d27f52" split="50"></podcast:valueRecipient>
376400
<podcast:valueRecipient name="Co-Host #2" type="node" address="032f4ffbbafffbe51726ad3c164a3d0d37ec27bc67b29a159b0f49ae8ac21b8508" split="40"></podcast:valueRecipient>
377401
<podcast:valueRecipient name="Producer" type="node" address="03ae9f91a0cb8ff43840e3c322c4c61f019d8c1c3cea15a25cfc425ac605e61a4a" split="10"></podcast:valueRecipient>
402+
<podcast:valueTimeSplit startTime="60" duration="237" remotePercentage="95">
403+
<podcast:remoteItem itemGuid="https://podcastindex.org/podcast/4148683#1" feedGuid="a94f5cc9-8c58-55fc-91fe-a324087a655b" medium="music"></podcast:remoteItem>
404+
</podcast:valueTimeSplit>
405+
<podcast:valueTimeSplit startTime="330" duration="53" remoteStartTime="174" remotePercentage="95">
406+
<podcast:remoteItem itemGuid="https://podcastindex.org/podcast/4148683#3" feedGuid="a94f5cc9-8c58-55fc-91fe-a324087a655b" medium="music"></podcast:remoteItem>
407+
</podcast:valueTimeSplit>
378408
</podcast:value>
379409
<item>
380410
<description>This is a simple episode &amp; its description.</description>

0 commit comments

Comments
 (0)