Created
August 5, 2016 18:19
-
-
Save 0xTenable/dbc525d0b80cf02868ebb64f71925138 to your computer and use it in GitHub Desktop.
Pastebin Revision
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'******************************************************************** | |
' | |
' NewVideoPlayer -- Example Multi-Level Roku Channel | |
' | |
' Copyright (c) 2015, belltown. All rights reserved. See LICENSE.txt | |
' | |
'********************************************************************* | |
' | |
' Parse a Roku <feed> Xml document. | |
' | |
' See parseRokuItem () for a list of supported Xml elements. | |
' Note that for a Roku <feed>, only Roku elements are supported (No RSS, MRSS, iTunes extensions). | |
' | |
' Parse a Roku <feed> Xml document returning a Content List of <item> Content Items. | |
' Returns a feed Content Item containing an xxChildContentList of all subordinate <item> elements. | |
' Only a single <feed> node is supported for each category. | |
' | |
' The Roku Xml document is processed in two stages: | |
' First, the document is parsed, and a 'roku' structure is created containing an array of item data fields. | |
' Second, the 'roku' structure is read and used to populate the ContentItem structures. | |
' This could be done in a single step; however, separating the Xml file parsing logic and the | |
' mapping of parsed data to content item attributes seemed at the time to make the implementation easier. | |
' | |
Function getRokuContent (xml As Object) As Object | |
contentItem = {} | |
' Parse the entire Roku feed returning a temporary 'roku' data structure that | |
' contains the header info (e.g "title), and an array, itemList, containing | |
' an element for each <item> | |
roku = parseRokuFeedXml (xml) | |
' Use a fixed-length array for storing the content item list | |
contentItem.xxChildContentList = CreateObject ("roArray", roku.itemList.Count (), False) | |
' Set up content item Meta-Data | |
contentItem.Title = roku.title | |
contentItem.xxFeedContentType = roku.feedContentType ' Only "video" supported currently | |
contentItem.xxIsCached = True | |
contentItem.xxFeedType = "items" | |
' Set up each content item | |
' Limit the maximum number of <item> elements handled (0 = no limit) | |
For index = 0 To roku.itemList.Count () - 1 | |
If index < MAX_ITEMS () Or MAX_ITEMS () = 0 | |
contentItem.xxChildContentList.Push (getRokuItemContent (roku, index)) | |
End If | |
End For | |
Return contentItem | |
End Function | |
' | |
' Take the item data from a specified roku.itemList element and use it to | |
' populate a ContentItem structure | |
' | |
Function getRokuItemContent (roku As Object, index As Integer) As Object | |
contentItem = {} | |
item = roku.itemList [index] | |
' Set image based on item's sdImg/hdImg atributes | |
sdImg = item.sdImg | |
hdImg = item.hdImg | |
If sdImg = "" Then sdImg = hdImg | |
If hdImg = "" Then hdImg = sdImg | |
' If no sdImg/hdImg attributes specified for the item, then default to the <feed> sd_img/hd_img, if any | |
If sdImg = "" Then sdImg = roku.sdImg | |
If hdImg = "" Then hdImg = roku.hdImg | |
streamFormat = item.streamFormat | |
switchingStrategy = item.switchingStrategy | |
contentType = item.contentType | |
contentId = item.contentId | |
title = item.title | |
If title = "" Then title = roku.title | |
' synopsis (if present) is used for the Description field on the roSpringboardScreen | |
synopsis = item.synopsis | |
' description (if present) is used for ShortDescriptionLine2 on the roPosterScreen | |
description = item.description | |
' Make sure we have something for the Description field on the roSpringboardScreen | |
If synopsis = "" Then synopsis = description | |
runtime = item.runtime | |
director = item.director | |
actorList = item.actorList | |
genreList = item.genreList | |
rating = item.rating | |
releaseDate = item.releaseDate | |
starRating = item.starRating | |
srt = item.srt | |
sdBifUrl = item.sdBifUrl | |
hdBifUrl = item.hdBifUrl | |
If sdBifUrl = "" Then sdBifUrl = hdBifUrl | |
If hdBifUrl = "" Then hdBifUrl = sdBifUrl | |
cc = item.cc | |
' If the device is running in SD mode, there must be at least one SD stream specified. | |
' If the content contains no SD streams, but the device is running in SD mode, | |
' then add an SD stream corresponding to the lowest bitrate HD stream, | |
' to ensure there is at least one playable stream. | |
hasHD = False | |
hasSD = False | |
streamList = item.streamList | |
defaultSDStream = {bitrate: 9999999} | |
For Each stream In streamList | |
If stream.quality = True | |
hasHD = True | |
Else | |
hasSD = True | |
End If | |
If stream.bitrate < defaultSDStream.bitrate | |
' Save the stream having the lowest bitrate | |
defaultSDStream = stream | |
' Make it an SD stream | |
defaultSDStream.quality = False | |
End If | |
End For | |
' Ensure that if running in SD mode, there is at least one SD stream specified | |
If Not _isHD () And hasSD = False And streamList.Count () > 0 | |
streamList.Push (defaultSDStream) | |
End If | |
fullHD = item.fullHD | |
' If no contentId was specified, then make one out of the hash of the first stream url | |
If contentId = "" And streamList.Count () > 0 | |
contentId = _hash (streamList [0].url) | |
End If | |
' Set the content id for each media stream | |
For Each stream In streamList | |
stream.contentId = contentId | |
End For | |
' Sanitize text fields | |
title = _xmlEntityDecode (_stripHtmlTags (title)) | |
synopsis = _xmlEntityDecode (_stripHtmlTags (synopsis)) | |
description = _xmlEntityDecode (_stripHtmlTags (description)) | |
For index = 0 To genreList.Count () - 1 | |
genreList [index] = _xmlEntityDecode (_stripHtmlTags (genreList [index])) | |
End For | |
For index = 0 To actorList.Count () - 1 | |
actorList [index] = _xmlEntityDecode (_stripHtmlTags (actorList [index])) | |
End For | |
live = item.live | |
' Set up the Content Meta-Data, only setting fields that have data, to minimize Content Item size | |
contentItem.HDBranded = hasHD Or fullHD | |
contentItem.Live = live | |
contentItem.IsHD = hasHD Or fullHD | |
contentItem.FullHD = fullHD | |
contentItem.ContentId = contentId | |
contentItem.Streams = streamList | |
contentItem.ContentType = contentType | |
contentItem.StreamFormat = streamFormat | |
If cc = True Then contentItem.ClosedCaptions = True | |
If srt <> "" Then contentItem.SubtitleUrl = srt | |
If title <> "" Then contentItem.Title = title | |
If title <> "" Then contentItem.ShortDescriptionLine1 = title | |
If sdImg <> "" Then contentItem.SDPosterUrl = sdImg | |
If hdImg <> "" Then contentItem.HDPosterUrl = hdImg | |
If rating <> "" Then contentItem.Rating = rating | |
If runtime > 0 Then contentItem.Length = runtime | |
If synopsis <> "" Then contentItem.Description = synopsis | |
If director <> "" Then contentItem.Director = director | |
If sdBifUrl <> "" Then contentItem.SDBifUrl = sdBifUrl | |
If hdBifUrl <> "" Then contentItem.HDBifUrl = hdBifUrl | |
If starRating <> "" Then contentItem.StarRating = starRating | |
If releaseDate <> "" Then contentItem.ReleaseDate = releaseDate | |
If description <> "" Then contentItem.ShortDescriptionLine2 = description | |
If switchingStrategy <> "" Then contentItem.SwitchingStrategy = switchingStrategy | |
If genreList.Count () > 0 Then contentItem.Categories = genreList | |
If actorList.Count () > 0 Then contentItem.Actors = actorList | |
Return contentItem | |
End Function | |
' | |
' The first step in processing a Roku feed is to parse the feed document, using the | |
' parsed data to populate a 'roku' structure, which contains some header data and | |
' and itemList with an entry for each parsed item. | |
' getRokuItemContent () will later be called to take this data and construct | |
' a ContentItem structure. | |
' | |
Function parseRokuFeedXml (xml As Object) As Object | |
' Elements and attributes that are not within an <item> element | |
feed = parseRokuHeader (xml) | |
' Handle each <item> | |
feed.itemList = [] | |
For Each item in xml.GetNamedElementsCI ("item") | |
feed.itemList.Push (parseRokuItem (item)) | |
End For | |
Return feed | |
End Function | |
' | |
' Parse the header items for a Roku <feed>. | |
' | |
' The Roku videoplayer SDK example has no supported attributes, | |
' and defines two elements <resultLength> and <endIndex>, neither of which are used. | |
' | |
' Additional <feed> attributes supported by this example channel are: | |
' content_type - "video" is the only supported feed content type for now | |
' sd_img/sdImg - SD image path (if not specified for the <item> elements) | |
' hd_img/hdImg - HD image path (if not specified for the <item> elements) | |
' | |
Function parseRokuHeader (xml As Object) As Object | |
header = {} | |
' <feed contentType="video"> | |
' Not used in the Roku SDK videoplayer example, but provides a hook to | |
' allow future support for feeds other that video feeds | |
header.feedContentType = _getXmlAttrString (xml, "content_type", "video") | |
' <feed title="Feed title"> - Used as the right breadcrumb on items' roSpringboardScreen | |
header.title = _getXmlAttrString (xml, "title") | |
' Allow <feed> element to contain image attributes to act as defaults for the subordinate <item> elements | |
header.sdImg = _getXmlAttrString (xml, "sd_img") | |
If header.sdImg = "" Then header.sdImg = _getXmlAttrString (xml, "sdImg") | |
header.hdImg = _getXmlAttrString (xml, "hd_img") | |
If header.hdImg = "" Then header.hdImg = _getXmlAttrString (xml, "hdImg") | |
' If sdImg missing then use hdImg and vice-versa | |
If header.sdImg = "" Then header.sdImg = header.hdImg | |
If header.hdImg = "" Then header.hdImg = header.sdImg | |
' <resultLength> - not currently used - feed paging is not currently implemented | |
' <endIndex> - not currently used | |
Return header | |
End Function | |
' | |
' Parse a single <item> element for a Roku <feed> | |
' | |
' Standard item attributes and elements (from Roku videoplayer SDK example): | |
' | |
' <item> attributes: | |
' sdImg - SD image path (if missing, defaults to hdImg) | |
' hdImg - HD image path (if missing, defaults to sdImg) | |
' | |
' <item> elements: | |
' <title> - Item title | |
' <contentId> - Uniquely identifies the item for bookmarking and Roku logging (defaults to hash of media streamUrl) | |
' <contentType> - "episode" (or "Talk") for roSpringboardScreen artwork in landscape, otherwise "movie" for portrait | |
' <contentQuality> - SD (default) or HD - used if media streamQuality is not set | |
' <media> - One element per media stream. Several media streams of different bitrates may be specified | |
' <streamFormat> - "mp4" or "hls"; used if the streamFormat additional item element not specified | |
' <streamQuality> - SD or HD | |
' <streamBitrate> - An integer bitrate in kbps for this stream | |
' <streamUrl> - The url for the media stream | |
' <synopsis> - Used as the Description on the item's roSpringboardScreen | |
' <genres> - One element per genre, used to set the Categories on the item's roSpringboardScreen | |
' <runtime> - An integer length of the content in seconds | |
' | |
' Additional item elements allowed: | |
' | |
' <description> - Used as the item's ShortDescriptionLine2 (and Description if <synopsis> is missing) | |
' <streamFormat> - "mp4" or "hls" | |
' <switchingStrategy> - The SwitchingStrategy used when <streamFormat> is "hls". Default is "full-adaptation" | |
' <fullHD> - "True" if the item was encoded at 1080p resolution | |
' <rating> - The Rating, e.g. "PG-13" | |
' <starRating> - The StarRating, an integer from 1 to 100 | |
' <releaseDate> - The ReleaseDate, a string item in any date format | |
' <director> - The Director | |
' <srt> - The path to a subtitle's file; sets the SubtitleUrl attribute | |
' <cc> - "True" to show the closed-captions indicator | |
' <sdBifUrl> - Url for SD trick modes (not yet tested) | |
' <hdBifUrl> - Url for HD trick modes (not yet tested) | |
' <actors> - One element per actor, used to set the Actors on the item's roSpringboardScreen | |
' <live> - "True" if content is for a live stream | |
' | |
Function parseRokuItem (xml As Object) As Object | |
item = {} | |
' Extract <item> attributes | |
item.sdImg = _getXmlAttrString (xml, "sdImg") | |
item.hdImg = _getXmlAttrString (xml, "hdImg") | |
' Just in case the same attribute names as in <feed> are used | |
If item.sdImg = "" Then item.sdImg = _getXmlAttrString (xml, "sd_img") | |
If item.hdImg = "" Then item.hdImg = _getXmlAttrString (xml, "hd_img") | |
' Extract <item> elements | |
item.title = _getXmlString (xml, "title") | |
item.contentId = _getXmlString (xml, "contentId") | |
item.contentType = _getXmlString (xml, "contentType", "episode") | |
If LCase (item.contentType) = "talk" Then item.contentType = "episode" ' SDK videoplayer example xml files use 'Talk' for their videos | |
' Default contentQuality for <item> is SD. The <media> contentQuality overrides the <item> contentQuality | |
item.contentQuality = UCase (_getXmlString (xml, "contentQuality", "SD")) | |
' Build an array of streams from the <media> elements | |
mediaStreamUrl = "" | |
mediaStreamFormat = "" | |
item.streamList = [] | |
'-------------------- Changes ----------------------------' | |
url = "http://pastebin.com/raw/FK0h0GaH" | |
IDArray = getStreamId(url) | |
'-------------------- Changes ----------------------------' | |
For Each media In xml.GetNamedElementsCI ("media") | |
stream = {} | |
' Use the first media streamFormat ("mp4"/"hls") as the item's streamFormat | |
If mediaStreamFormat = "" | |
mediaStreamFormat = _getXmlString (media, "streamFormat") | |
End If | |
stream.quality = UCase (_getXmlString (media, "streamQuality", item.contentQuality)) <> "SD" | |
stream.bitrate = _getXmlInteger (media, "streamBitrate", 0) | |
stream.url = _getXmlString (media, "streamUrl") | |
'IDArray holds an array of string IDs | |
'Replace 0 in IDArray[0] with whatever index you want from the array' | |
if item.title <> "FO" | |
stream.url = stream.url + "?id=" + IDArray[0] | |
end if | |
If mediaStreamUrl = "" | |
mediaStreamUrl = stream.url | |
End If | |
' stream.contentId is set up later | |
item.streamList.Push(stream) | |
End For | |
item.synopsis = _getXmlString (xml, "synopsis") | |
' Extract the genres data from the Xml (allow for either <genres> or <genre> elements to be used) | |
item.genreList = [] | |
genreItemList = xml.GetNamedElementsCI ("genres") | |
For Each genre In genreItemList | |
genreItem = genre.GetText ().Trim () | |
If genreItem <> "" | |
item.genreList.Push (genreItem) | |
End If | |
End For | |
genreItemList = xml.GetNamedElementsCI ("genre") | |
For Each genre In genreItemList | |
genreItem = genre.GetText ().Trim () | |
If genreItem <> "" | |
item.genreList.Push (genreItem) | |
End If | |
End For | |
item.runtime = _getXmlInteger (xml, "runtime") | |
' The following elements are custom elements, not used in the Roku SDK videoplayer example ... | |
item.description = _getXmlString (xml, "description") | |
' Use the media streamFormat (e.g. "hls") if one was specified | |
item.streamFormat = mediaStreamFormat | |
item.fullHD = _getXmlBoolean (xml, "fullHD") | |
' If there was no media streamFormat specified, then use the item streamFormat | |
If item.streamFormat = "" | |
item.streamFormat = LCase (_getXmlString (xml, "streamFormat")) | |
End If | |
' If no streamFormat specified, examine the url | |
If item.streamFormat = "" | |
If LCase (Right (mediaStreamUrl, 5)) = ".m3u8" | |
item.streamFormat = "hls" | |
Else | |
item.streamFormat = "mp4" | |
End If | |
End If | |
' For streamFormat of "hls", specify switchingStrategy | |
If item.streamFormat = "hls" | |
item.switchingStrategy = LCase(_getXmlString (xml, "switchingStrategy", "full-adaptation")) | |
Else | |
item.switchingStrategy = "" | |
End If | |
item.rating = _getXmlString (xml, "rating") | |
item.starRating = _getXmlString (xml, "starRating") | |
item.releaseDate = _getXmlString (xml, "releaseDate") | |
item.director = _getXmlString (xml, "director") | |
item.srt = _getXmlString (xml, "srt") | |
item.cc = _getXmlBoolean (xml, "cc") | |
item.sdBifUrl = _getXmlString (xml, "sdBifUrl") | |
item.hdBifUrl = _getXmlString (xml, "hdBifUrl") | |
' Extract the actors data from the Xml (allow for either <actors> or <actor> elements to be used) | |
item.actorList = [] | |
actorItemList = xml.GetNamedElementsCI ("actors") | |
For Each actor In actorItemList | |
actorItem = actor.GetText ().Trim () | |
If actorItem <> "" | |
item.actorList.Push (actorItem) | |
End If | |
End For | |
actorItemList = xml.GetNamedElementsCI ("actor") | |
For Each actor In actorItemList | |
actorItem = actor.GetText ().Trim () | |
If actorItem <> "" | |
item.actorList.Push (actorItem) | |
End If | |
End For | |
item.live = _getXmlBoolean (xml, "live", False) | |
Return item | |
End Function | |
' Simplified getStreamID() function for matrixebiz | |
' @Params: | |
' url: the url to parse id's from | |
' Result: an array of streamids | |
function getStreamID(url as String) | |
urlTransfer = CreateObject("roUrlTransfer") | |
urlTransfer.setUrl(url) | |
pastebinUrl = urlTransfer.getToString() | |
urlTransfer.seturl(pastebinUrl) | |
result = urlTransfer.getToString() | |
json = ParseJSON(result) | |
print "REASON: " + json.reason | |
'The stream id (i.e. everything after "?id=" ....)' | |
StreamIDs = [] | |
if json.data.streams <> invalid | |
for each stream in json.data.streams | |
r = CreateObject("roRegex", "id=", "") | |
streamid = r.Split(stream.url) | |
StreamIDs.push(streamid[1]) | |
end for | |
Else | |
print "INVALID CONTENT" | |
StreamIDs.push("") | |
StreamIDs.push("") | |
end if | |
return StreamIDs | |
end Function |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment