Mon Oct 29, 2012 11:07 pm by gonzo90017
I saw that thread earlier but still can't get the feeds to work properly. I copied Hulu.grooovy and pasted it in the plugins folder. I then renamed it to HuluPipes.groovy. This is what it looks like:
- Code:
import groovy.util.XmlParser
import org.serviio.library.metadata.*
import org.serviio.library.online.*
/**
* Hulu.com content URL extractor plugin.
*
* Based on http://gitorious.org/get-flash-videos-plugins/gfv-plugins/blobs/raw/release/Hulu.pm
*
* @author Petr Nejedly
*
*/
class Hulu extends FeedItemUrlExtractor {
final VALID_FEED_URL = '(http:\\/\\/pipes\\.yahoo\\.com\\/pipes\\/pipe\\.run\\?_id=xxxxxxxxxxxxxxxxx&_render=rss)'
final PLAYER_VERSION = '888324234'
final PLAYER_URL = 'http://www.hulu.com/site-player/player.swf'
final SMIL_KEY = 'd6dac049cc944519806ab9a1b5e29ccfe3e74dabb4fa42598a45c35d20abdd28';
final SMIL_IV = '27b9bedf75ccA2eC';
String getExtractorName() {
return 'Hulu (US only)'
}
boolean extractorMatches(URL feedUrl) {
return feedUrl ==~ VALID_FEED_URL
}
ContentURLContainer extractUrl(Map links, PreferredQuality requestedQuality) {
def linkUrl = links.default
def contentUrl
def cacheKey
String pageHtml = linkUrl.getText()
String regex = "www.hulu.com/embed.html\\?eid=?([a-zA-Z0-9-_]+)"
def pageMatcher = pageHtml =~ regex
assert pageMatcher != null
def eId = pageMatcher[0][1]
String rUrl = "http://r.hulu.com/videos?eid=$eId"
def contentDetailsNode = new XmlParser().parse( rUrl )
def videoId = contentDetailsNode.video.'content-id'.text()
Integer timestamp = (System.currentTimeMillis() / 1000) + (24 * 60 * 60);
String bcsRaw = "dp_idhulunp1pphuluts${timestamp}v${PLAYER_VERSION}video_id${videoId}vp1"
String bcs = generateMAC(bcsRaw,'f6daaa397d51f568dd068709b0ce8e93293e078f7dfc3b40dd8c32d36d2b3ce1','HmacMD5')
String smilFileUrl = "http://s.hulu.com/select.ashx?video_id=${videoId}&v=${PLAYER_VERSION}&ts=${timestamp}&np=1&vp=1&pp=hulu&dp_id=hulu&bcs=${bcs}"
def smilContent = new URL(smilFileUrl).getText()
String decodedSmil = trimSmilXml(decryptAES(smilContent, SMIL_KEY, SMIL_IV))
assert decodedSmil != null
def smilNode = new XmlParser().parseText( decodedSmil )
// get all media items that are either video or audio and have a supported connection sub-element
List mediaItems = smilNode.body.'switch'[1].video.findAll { it -> (it.'@cdn' == 'akamai') }
assert mediaItems.size() > 0 : 'No video sources found, you are probably outside the US'
// sort media items by bitrate, lowest first and get an item
List sortedItems = mediaItems.sort { it.'@system-bitrate'.toInteger() }
Node selectedMediaItem = findSuitableItem(sortedItems, requestedQuality)
String app = (selectedMediaItem.'@server' =~ 'rtmpe?://.*?/(.*)')[0][1]
contentUrl = "${selectedMediaItem.'@server'}?${selectedMediaItem.'@token'} app=${app}?${selectedMediaItem.'@token'} playpath=${selectedMediaItem.'@stream'} swfUrl=${PLAYER_URL} swfVfy=1"
cacheKey = "hulu_${videoId}_${requestedQuality}"
return new ContentURLContainer(contentUrl: contentUrl, expiresImmediately: true, cacheKey : cacheKey)
}
def Node findSuitableItem(List items, PreferredQuality requestedQuality) {
if(requestedQuality == PreferredQuality.LOW) {
// worst quality, get the first from the list
return items.head()
} else if (requestedQuality == PreferredQuality.MEDIUM) {
// get item from the middle
return items.get(Math.floor(items.size()/2).toInteger())
} else {
// best quality, take the last url
return items.last()
}
}
def String trimSmilXml(String smil) {
def matcher = smil =~ '(?s)^<smil.*</smil>'
//log(smil)
assert matcher != null
assert matcher.count == 1 : 'Invalid SMIL XML, content probably expired'
return matcher[0]
}
static void main(args) {
// this is just to test
Hulu extractor = new Hulu()
assert extractor.extractorMatches( new URL("http://www.hulu.com/feed/recent/tv") )
assert extractor.extractorMatches( new URL("http://rss.hulu.com/HuluPopularVideosThisWeek?format=xml") )
Map links = ['default': new URL('http://rss.hulu.com/~r/HuluPopularVideosThisWeek/~3/VGE00M3j8Rk/406212')]
//Map links = ['default': new URL('http://www.hulu.com/watch/59796/emergency-back-up#http%3A%2F%2Fwww.hulu.com%2Ffeed%2Fshow%2F172%2Fepisodes')]
ContentURLContainer result = extractor.extractUrl(links, PreferredQuality.MEDIUM)
println "Result: $result"
}
}
Did I do it right, miss something or skip a step?