syndicate 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +8 -0
- data/Rakefile +2 -0
- data/bin/syndicate +5 -0
- data/examples/roku/Makefile +23 -0
- data/examples/roku/README.md +24 -0
- data/examples/roku/app.mk +89 -0
- data/examples/roku/images/banner-hd.png +0 -0
- data/examples/roku/images/banner-logo-hd.png +0 -0
- data/examples/roku/images/banner-logo-sd.png +0 -0
- data/examples/roku/images/banner-sd.png +0 -0
- data/examples/roku/images/logo-hd.jpg +0 -0
- data/examples/roku/images/logo-sd.jpg +0 -0
- data/examples/roku/manifest +9 -0
- data/examples/roku/source/appMain.brs +13 -0
- data/examples/roku/source/lib/generalDlgs.brs +150 -0
- data/examples/roku/source/lib/generalUtils.brs +681 -0
- data/examples/roku/source/lib/lib.brs +45 -0
- data/examples/roku/source/lib/mrss.brs +59 -0
- data/examples/roku/source/lib/urlUtils.brs +215 -0
- data/examples/roku/source/lib/video.brs +17 -0
- data/examples/roku/source/screens/mediaplayer.brs +36 -0
- data/examples/roku/source/screens/poster.brs +65 -0
- data/examples/roku/source/theme.brs +30 -0
- data/lib/syndicate.rb +7 -0
- data/lib/syndicate/app.rb +40 -0
- data/lib/syndicate/config.ru +6 -0
- data/lib/syndicate/lib/video.rb +37 -0
- data/lib/syndicate/version.rb +3 -0
- data/lib/syndicate/views/mrss.builder +16 -0
- data/syndicate.gemspec +21 -0
- metadata +129 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
'Library of Shared Functions
|
2
|
+
|
3
|
+
'Creates connection and retrieve url over http
|
4
|
+
Function initConnection(url As String) As String
|
5
|
+
|
6
|
+
conn = CreateObject("roAssociativeArray")
|
7
|
+
|
8
|
+
conn.Url = url
|
9
|
+
print "Initializing connection to" + conn.Url
|
10
|
+
conn.Timer = CreateObject("roTimespan")
|
11
|
+
|
12
|
+
'print "created feed connection for " + conn.Url
|
13
|
+
http = NewHttp(conn.Url)
|
14
|
+
|
15
|
+
'print "Getting http response"
|
16
|
+
rsp = http.GetToStringWithRetry()
|
17
|
+
'print rsp
|
18
|
+
|
19
|
+
return rsp
|
20
|
+
End Function
|
21
|
+
|
22
|
+
'Creates XML object out of string
|
23
|
+
Function to_xml(rsp As String) As Object
|
24
|
+
xml = CreateObject("roXMLElement")
|
25
|
+
if not xml.Parse(rsp) then
|
26
|
+
'print "Invalid XML"
|
27
|
+
return invalid
|
28
|
+
endif
|
29
|
+
|
30
|
+
return xml
|
31
|
+
End Function
|
32
|
+
|
33
|
+
Function comma_seperate(string1 As String, string2 As String) As String
|
34
|
+
str = CreateObject("roString")
|
35
|
+
|
36
|
+
if (string1.Len() > 0 AND string2.Len() > 0) then
|
37
|
+
str = string1 + ", " + string2
|
38
|
+
else if (string1.Len() <= 0 AND string2.Len() > 0) then
|
39
|
+
str = string2
|
40
|
+
else if (string1.Len() > 0 AND string2.Len() <= 0) then
|
41
|
+
str = string1
|
42
|
+
end if
|
43
|
+
|
44
|
+
return str
|
45
|
+
End Function
|
@@ -0,0 +1,59 @@
|
|
1
|
+
Function getMRSS(url As Object) As Object
|
2
|
+
feed = initConnection(url)
|
3
|
+
videos = parseVideos( to_xml(feed) )
|
4
|
+
|
5
|
+
return videos
|
6
|
+
End Function
|
7
|
+
|
8
|
+
Function parseVideos(xml as Object) As Object
|
9
|
+
videos = CreateObject("roArray", 100, true)
|
10
|
+
|
11
|
+
if xml = invalid then
|
12
|
+
print "Error Retrieving XML"
|
13
|
+
return videos
|
14
|
+
endif
|
15
|
+
|
16
|
+
if xml.GetName() <> "channel" then
|
17
|
+
print "No channel tag found."
|
18
|
+
return videos
|
19
|
+
endif
|
20
|
+
|
21
|
+
'stop
|
22
|
+
|
23
|
+
for each item in xml.GetNamedElements("item")
|
24
|
+
'stop
|
25
|
+
video = initVideoItem()
|
26
|
+
'video.ContentId = curVideo.id.GetText()
|
27
|
+
title = item.GetNamedElements("media:title")
|
28
|
+
video.Title = title.GetText()
|
29
|
+
video.Description = item.description.GetText()
|
30
|
+
'video.StreamFormat = curVideo.format.GetText()
|
31
|
+
video.StreamFormat = "mp4"
|
32
|
+
'video.Length = curVideo.runtime.GetText()
|
33
|
+
'video.Quality = curVideo.quality.GetText()
|
34
|
+
'video.SDPosterUrl = curVideo.sd_image.GetText()
|
35
|
+
'video.HDPosterUrl = curVideo.hd_image.GetText()
|
36
|
+
|
37
|
+
video.StreamUrls[0] = item.content.GetAttributes().url
|
38
|
+
video.streamQualities[0] = "SD"
|
39
|
+
video.StreamBitrates = 0
|
40
|
+
'n = 0
|
41
|
+
'streams = item.medias.GetChildElements()
|
42
|
+
'for each curStream in streams
|
43
|
+
'video.StreamQualities[n] = curStream.quality.GetText()
|
44
|
+
'video.StreamBitrates[n] = curStream.bitrate.GetText()
|
45
|
+
'video.StreamUrls[n] = curStream.url.GetText()
|
46
|
+
'video.StreamContentIDs[n] = curStream.id.GetText()
|
47
|
+
'n = n + 1
|
48
|
+
'next
|
49
|
+
|
50
|
+
video.ShortDescriptionLine2 = video.Description
|
51
|
+
video.ShortDescriptionLine1 = video.Title
|
52
|
+
|
53
|
+
print video
|
54
|
+
|
55
|
+
videos.Push(video)
|
56
|
+
next
|
57
|
+
|
58
|
+
return videos
|
59
|
+
End Function
|
@@ -0,0 +1,215 @@
|
|
1
|
+
'**********************************************************
|
2
|
+
'** Video Player Example Application - URL Utilities
|
3
|
+
'** November 2009
|
4
|
+
'** Copyright (c) 2009 Roku Inc. All Rights Reserved.
|
5
|
+
'**********************************************************
|
6
|
+
|
7
|
+
REM ******************************************************
|
8
|
+
REM Constucts a URL Transfer object
|
9
|
+
REM ******************************************************
|
10
|
+
|
11
|
+
Function CreateURLTransferObject(url As String) as Object
|
12
|
+
obj = CreateObject("roUrlTransfer")
|
13
|
+
obj.SetPort(CreateObject("roMessagePort"))
|
14
|
+
obj.SetUrl(url)
|
15
|
+
obj.AddHeader("Content-Type", "application/x-www-form-urlencoded")
|
16
|
+
obj.EnableEncodings(true)
|
17
|
+
return obj
|
18
|
+
End Function
|
19
|
+
|
20
|
+
REM ******************************************************
|
21
|
+
REM Url Query builder
|
22
|
+
REM so this is a quick and dirty name/value encoder/accumulator
|
23
|
+
REM ******************************************************
|
24
|
+
|
25
|
+
Function NewHttp(url As String) as Object
|
26
|
+
obj = CreateObject("roAssociativeArray")
|
27
|
+
obj.Http = CreateURLTransferObject(url)
|
28
|
+
obj.FirstParam = true
|
29
|
+
obj.AddParam = http_add_param
|
30
|
+
obj.AddRawQuery = http_add_raw_query
|
31
|
+
obj.GetToStringWithRetry = http_get_to_string_with_retry
|
32
|
+
obj.PrepareUrlForQuery = http_prepare_url_for_query
|
33
|
+
obj.GetToStringWithTimeout = http_get_to_string_with_timeout
|
34
|
+
obj.PostFromStringWithTimeout = http_post_from_string_with_timeout
|
35
|
+
|
36
|
+
if Instr(1, url, "?") > 0 then obj.FirstParam = false
|
37
|
+
|
38
|
+
return obj
|
39
|
+
End Function
|
40
|
+
|
41
|
+
|
42
|
+
REM ******************************************************
|
43
|
+
REM Constucts a URL Transfer object 2
|
44
|
+
REM ******************************************************
|
45
|
+
|
46
|
+
Function CreateURLTransferObject2(url As String, contentHeader As String) as Object
|
47
|
+
obj = CreateObject("roUrlTransfer")
|
48
|
+
obj.SetPort(CreateObject("roMessagePort"))
|
49
|
+
obj.SetUrl(url)
|
50
|
+
obj.AddHeader("Content-Type", contentHeader)
|
51
|
+
obj.EnableEncodings(true)
|
52
|
+
return obj
|
53
|
+
End Function
|
54
|
+
|
55
|
+
REM ******************************************************
|
56
|
+
REM Url Query builder 2
|
57
|
+
REM so this is a quick and dirty name/value encoder/accumulator
|
58
|
+
REM ******************************************************
|
59
|
+
|
60
|
+
Function NewHttp2(url As String, contentHeader As String) as Object
|
61
|
+
obj = CreateObject("roAssociativeArray")
|
62
|
+
obj.Http = CreateURLTransferObject2(url, contentHeader)
|
63
|
+
obj.FirstParam = true
|
64
|
+
obj.AddParam = http_add_param
|
65
|
+
obj.AddRawQuery = http_add_raw_query
|
66
|
+
obj.GetToStringWithRetry = http_get_to_string_with_retry
|
67
|
+
obj.PrepareUrlForQuery = http_prepare_url_for_query
|
68
|
+
obj.GetToStringWithTimeout = http_get_to_string_with_timeout
|
69
|
+
obj.PostFromStringWithTimeout = http_post_from_string_with_timeout
|
70
|
+
|
71
|
+
if Instr(1, url, "?") > 0 then obj.FirstParam = false
|
72
|
+
|
73
|
+
return obj
|
74
|
+
End Function
|
75
|
+
|
76
|
+
|
77
|
+
REM ******************************************************
|
78
|
+
REM HttpEncode - just encode a string
|
79
|
+
REM ******************************************************
|
80
|
+
|
81
|
+
Function HttpEncode(str As String) As String
|
82
|
+
o = CreateObject("roUrlTransfer")
|
83
|
+
return o.Escape(str)
|
84
|
+
End Function
|
85
|
+
|
86
|
+
REM ******************************************************
|
87
|
+
REM Prepare the current url for adding query parameters
|
88
|
+
REM Automatically add a '?' or '&' as necessary
|
89
|
+
REM ******************************************************
|
90
|
+
|
91
|
+
Function http_prepare_url_for_query() As String
|
92
|
+
url = m.Http.GetUrl()
|
93
|
+
if m.FirstParam then
|
94
|
+
url = url + "?"
|
95
|
+
m.FirstParam = false
|
96
|
+
else
|
97
|
+
url = url + "&"
|
98
|
+
endif
|
99
|
+
m.Http.SetUrl(url)
|
100
|
+
return url
|
101
|
+
End Function
|
102
|
+
|
103
|
+
REM ******************************************************
|
104
|
+
REM Percent encode a name/value parameter pair and add the
|
105
|
+
REM the query portion of the current url
|
106
|
+
REM Automatically add a '?' or '&' as necessary
|
107
|
+
REM Prevent duplicate parameters
|
108
|
+
REM ******************************************************
|
109
|
+
|
110
|
+
Function http_add_param(name As String, val As String) as Void
|
111
|
+
q = m.Http.Escape(name)
|
112
|
+
q = q + "="
|
113
|
+
url = m.Http.GetUrl()
|
114
|
+
if Instr(1, url, q) > 0 return 'Parameter already present
|
115
|
+
q = q + m.Http.Escape(val)
|
116
|
+
m.AddRawQuery(q)
|
117
|
+
End Function
|
118
|
+
|
119
|
+
REM ******************************************************
|
120
|
+
REM Tack a raw query string onto the end of the current url
|
121
|
+
REM Automatically add a '?' or '&' as necessary
|
122
|
+
REM ******************************************************
|
123
|
+
|
124
|
+
Function http_add_raw_query(query As String) as Void
|
125
|
+
url = m.PrepareUrlForQuery()
|
126
|
+
url = url + query
|
127
|
+
m.Http.SetUrl(url)
|
128
|
+
End Function
|
129
|
+
|
130
|
+
REM ******************************************************
|
131
|
+
REM Performs Http.AsyncGetToString() in a retry loop
|
132
|
+
REM with exponential backoff. To the outside
|
133
|
+
REM world this appears as a synchronous API.
|
134
|
+
REM ******************************************************
|
135
|
+
|
136
|
+
Function http_get_to_string_with_retry() as String
|
137
|
+
timeout% = 1500
|
138
|
+
num_retries% = 5
|
139
|
+
|
140
|
+
str = ""
|
141
|
+
while num_retries% > 0
|
142
|
+
' print "httpget try " + itostr(num_retries%)
|
143
|
+
if (m.Http.AsyncGetToString())
|
144
|
+
event = wait(timeout%, m.Http.GetPort())
|
145
|
+
if type(event) = "roUrlEvent"
|
146
|
+
str = event.GetString()
|
147
|
+
exit while
|
148
|
+
elseif event = invalid
|
149
|
+
m.Http.AsyncCancel()
|
150
|
+
REM reset the connection on timeouts
|
151
|
+
m.Http = CreateURLTransferObject(m.Http.GetUrl())
|
152
|
+
timeout% = 2 * timeout%
|
153
|
+
else
|
154
|
+
print "roUrlTransfer::AsyncGetToString(): unknown event"
|
155
|
+
endif
|
156
|
+
endif
|
157
|
+
|
158
|
+
num_retries% = num_retries% - 1
|
159
|
+
end while
|
160
|
+
|
161
|
+
return str
|
162
|
+
End Function
|
163
|
+
|
164
|
+
REM ******************************************************
|
165
|
+
REM Performs Http.AsyncGetToString() with a single timeout in seconds
|
166
|
+
REM To the outside world this appears as a synchronous API.
|
167
|
+
REM ******************************************************
|
168
|
+
|
169
|
+
Function http_get_to_string_with_timeout(seconds as Integer) as String
|
170
|
+
timeout% = 1000 * seconds
|
171
|
+
|
172
|
+
str = ""
|
173
|
+
m.Http.EnableFreshConnection(true) 'Don't reuse existing connections
|
174
|
+
if (m.Http.AsyncGetToString())
|
175
|
+
event = wait(timeout%, m.Http.GetPort())
|
176
|
+
if type(event) = "roUrlEvent"
|
177
|
+
str = event.GetString()
|
178
|
+
elseif event = invalid
|
179
|
+
Dbg("AsyncGetToString timeout")
|
180
|
+
m.Http.AsyncCancel()
|
181
|
+
else
|
182
|
+
Dbg("AsyncGetToString unknown event", event)
|
183
|
+
endif
|
184
|
+
endif
|
185
|
+
|
186
|
+
return str
|
187
|
+
End Function
|
188
|
+
|
189
|
+
REM ******************************************************
|
190
|
+
REM Performs Http.AsyncPostFromString() with a single timeout in seconds
|
191
|
+
REM To the outside world this appears as a synchronous API.
|
192
|
+
REM ******************************************************
|
193
|
+
|
194
|
+
Function http_post_from_string_with_timeout(val As String, seconds as Integer) as String
|
195
|
+
timeout% = 1000 * seconds
|
196
|
+
|
197
|
+
str = ""
|
198
|
+
' m.Http.EnableFreshConnection(true) 'Don't reuse existing connections
|
199
|
+
if (m.Http.AsyncPostFromString(val))
|
200
|
+
event = wait(timeout%, m.Http.GetPort())
|
201
|
+
if type(event) = "roUrlEvent"
|
202
|
+
print "1"
|
203
|
+
str = event.GetString()
|
204
|
+
elseif event = invalid
|
205
|
+
print "2"
|
206
|
+
Dbg("AsyncPostFromString timeout")
|
207
|
+
m.Http.AsyncCancel()
|
208
|
+
else
|
209
|
+
print "3"
|
210
|
+
Dbg("AsyncPostFromString unknown event", event)
|
211
|
+
endif
|
212
|
+
endif
|
213
|
+
|
214
|
+
return str
|
215
|
+
End Function
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Function initVideoItem() As Object
|
2
|
+
o = CreateObject("roAssociativeArray")
|
3
|
+
|
4
|
+
o.ContentId = ""
|
5
|
+
o.Title = ""
|
6
|
+
o.Description = ""
|
7
|
+
o.StreamFormat = ""
|
8
|
+
o.Live = false
|
9
|
+
o.Length = ""
|
10
|
+
o.SDImageUrl = ""
|
11
|
+
o.HDImageUrl = ""
|
12
|
+
o.StreamQualities = CreateObject("roArray", 5, true)
|
13
|
+
o.StreamBitrates = CreateObject("roArray", 5, true)
|
14
|
+
o.StreamUrls = CreateObject("roArray", 5, true)
|
15
|
+
o.StreamContentIDs = CreateObject("roArray", 5, true)
|
16
|
+
return o
|
17
|
+
End Function
|
@@ -0,0 +1,36 @@
|
|
1
|
+
Function showMediaPlayer(video As Object)
|
2
|
+
port = CreateObject("roMessagePort")
|
3
|
+
screen = CreateObject("roVideoScreen")
|
4
|
+
screen.SetMessagePort(port)
|
5
|
+
|
6
|
+
screen.SetPositionNotificationPeriod(30)
|
7
|
+
screen.SetContent(video)
|
8
|
+
screen.Show()
|
9
|
+
|
10
|
+
'Uncomment his line to dump the contents of the video to be played
|
11
|
+
PrintAA(video)
|
12
|
+
|
13
|
+
while true
|
14
|
+
msg = wait(0, port)
|
15
|
+
|
16
|
+
if type(msg) = "roVideoScreenEvent" then
|
17
|
+
if msg.isScreenClosed()
|
18
|
+
print "Screen closed"
|
19
|
+
exit while
|
20
|
+
elseif msg.isRequestFailed()
|
21
|
+
print "Video request failure: "; msg.GetIndex(); " " msg.GetData()
|
22
|
+
elseif msg.isStatusMessage()
|
23
|
+
print "Video status: "; msg.GetIndex(); " " msg.GetData()
|
24
|
+
elseif msg.isButtonPressed()
|
25
|
+
print "Button pressed: "; msg.GetIndex(); " " msg.GetData()
|
26
|
+
elseif msg.isPlaybackPosition() then
|
27
|
+
nowpos = msg.GetIndex()
|
28
|
+
'RegWrite(video.ContentId, nowpos.toStr())
|
29
|
+
else
|
30
|
+
print "Unexpected event type: "; msg.GetType()
|
31
|
+
end if
|
32
|
+
else
|
33
|
+
print "Unexpected message class: "; type(msg)
|
34
|
+
end if
|
35
|
+
end while
|
36
|
+
End Function
|
@@ -0,0 +1,65 @@
|
|
1
|
+
'******************************************************
|
2
|
+
'** Video Player Example Application -- Poster Screen
|
3
|
+
'** November 2009
|
4
|
+
'** Copyright (c) 2009 Roku Inc. All Rights Reserved.
|
5
|
+
'******************************************************
|
6
|
+
|
7
|
+
'******************************************************
|
8
|
+
'** Perform any startup/initialization stuff prior to
|
9
|
+
'** initially showing the screen.
|
10
|
+
'******************************************************
|
11
|
+
Function prePosterScreen(breadA=invalid, breadB=invalid) As Object
|
12
|
+
port=CreateObject("roMessagePort")
|
13
|
+
screen = CreateObject("roPosterScreen")
|
14
|
+
screen.SetMessagePort(port)
|
15
|
+
if breadA<>invalid and breadB<>invalid then
|
16
|
+
screen.SetBreadcrumbText(breadA, breadB)
|
17
|
+
end if
|
18
|
+
|
19
|
+
screen.SetListStyle("flat-category")
|
20
|
+
screen.SetListDisplayMode("photo-fit")
|
21
|
+
|
22
|
+
return screen
|
23
|
+
End Function
|
24
|
+
|
25
|
+
|
26
|
+
'******************************************************
|
27
|
+
'** Display the home screen and wait for events from
|
28
|
+
'** the screen. The screen will show retreiving while
|
29
|
+
'** we fetch and parse the feeds for the game posters
|
30
|
+
'******************************************************
|
31
|
+
Function showPosterScreen(screen As Object, feedURL As String) As Integer
|
32
|
+
curVideo = 0
|
33
|
+
|
34
|
+
videos = getMRSS(feedURL)
|
35
|
+
|
36
|
+
if videos.Count() > 0 then
|
37
|
+
screen.SetContentList(videos)
|
38
|
+
else
|
39
|
+
screen.ShowMessage("No videos found for this channel")
|
40
|
+
end if
|
41
|
+
|
42
|
+
screen.Show()
|
43
|
+
|
44
|
+
while true
|
45
|
+
print "POSTER SCREEN!"
|
46
|
+
|
47
|
+
msg = wait(0, screen.GetMessagePort())
|
48
|
+
if type(msg) = "roPosterScreenEvent" then
|
49
|
+
print "showPosterScreen | msg = "; msg.GetMessage() " | index = "; msg.GetIndex()
|
50
|
+
print msg.GetMessage()
|
51
|
+
print "POSTER SCREEN! MSG"
|
52
|
+
|
53
|
+
if msg.isListFocused() then
|
54
|
+
curVideo = 0
|
55
|
+
screen.SetFocusedListItem(curVideo)
|
56
|
+
else if msg.isListItemSelected() then
|
57
|
+
curVideo = msg.GetIndex()
|
58
|
+
showMediaPlayer(videos[curVideo])
|
59
|
+
else if msg.isScreenClosed() then
|
60
|
+
print "Screen Closed!"
|
61
|
+
return -1
|
62
|
+
end if
|
63
|
+
end If
|
64
|
+
end while
|
65
|
+
End Function
|
@@ -0,0 +1,30 @@
|
|
1
|
+
'*************************************************************
|
2
|
+
'** Set the configurable theme attributes for the application
|
3
|
+
'**
|
4
|
+
'** Configure the custom overhang and Logo attributes
|
5
|
+
'** Theme attributes affect the branding of the application
|
6
|
+
'** and are artwork, colors and offsets specific to the app
|
7
|
+
'*************************************************************
|
8
|
+
|
9
|
+
Sub initTheme()
|
10
|
+
|
11
|
+
app = CreateObject("roAppManager")
|
12
|
+
theme = CreateObject("roAssociativeArray")
|
13
|
+
|
14
|
+
theme.OverhangOffsetSD_X = "45"
|
15
|
+
theme.OverhangOffsetSD_Y = "30"
|
16
|
+
theme.OverhangSliceSD = "pkg:/images/banner-sd.png"
|
17
|
+
theme.OverhangLogoSD = "pkg:/images/banner-logo-sd.png"
|
18
|
+
|
19
|
+
theme.OverhangOffsetHD_X = "75"
|
20
|
+
theme.OverhangOffsetHD_Y = "40"
|
21
|
+
theme.OverhangSliceHD = "pkg:/images/banner-hd.png"
|
22
|
+
theme.OverhangLogoHD = "pkg:/images/banner-logo-hd.png"
|
23
|
+
|
24
|
+
theme.FilterBannerActiveColor = "#FFFFFF"
|
25
|
+
theme.FilterBannerInactiveColor = "#0055a0"
|
26
|
+
theme.FilterBannerSideColor = "#0055a0"
|
27
|
+
|
28
|
+
app.SetTheme(theme)
|
29
|
+
|
30
|
+
End Sub
|