Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import xbmcplugin
- import xbmc
- import xbmcgui
- import addoncompat
- import urllib
- import urllib2
- import sys
- import os
- import cookielib
- import operator
- import re
- import time
- import random
- from crypto.cipher.cbc import CBC
- from crypto.cipher.base import padWithPadLen
- from crypto.cipher.rijndael import Rijndael
- try:
- from xml.etree import ElementTree
- except:
- from elementtree import ElementTree
- """
- PARSE ARGV
- """
- class _Info:
- def __init__( self, *args, **kwargs ):
- self.__dict__.update( kwargs )
- exec "args = _Info(%s)" % (urllib.unquote_plus(sys.argv[2][1:].replace("&", ", ").replace('"','\'').replace('%5C', '%5C%5C')), )
- """
- DEFINE URLS
- """
- BASE_MENU_URL = "http://m.hulu.com/menu/hd_main_menu?show_id=0&dp_id=huludesktop&package_id=2&page=1"
- xmldeckeys = [
- ['4878B22E76379B55C962B18DDBC188D82299F8F52E3E698D0FAF29A40ED64B21', 'WA7hap7AGUkevuth'],
- ['246DB3463FC56FDBAD60148057CB9055A647C13C02C64A5ED4A68F81AE991BF5', 'vyf8PvpfXZPjc7B1'],
- ['8CE8829F908C2DFAB8B3407A551CB58EBC19B07F535651A37EBC30DEC33F76A2', 'O3r9EAcyEeWlm5yV'],
- ['852AEA267B737642F4AE37F5ADDF7BD93921B65FE0209E47217987468602F337', 'qZRiIfTjIGi3MuJA'],
- ['76A9FDA209D4C9DCDFDDD909623D1937F665D0270F4D3F5CA81AD2731996792F', 'd9af949851afde8c'],
- ['1F0FF021B7A04B96B4AB84CCFD7480DFA7A972C120554A25970F49B6BADD2F4F', 'tqo8cxuvpqc7irjw'],
- ['3484509D6B0B4816A6CFACB117A7F3C842268DF89FCC414F821B291B84B0CA71', 'SUxSFjNUavzKIWSh'],
- ['B7F67F4B985240FAB70FF1911FCBB48170F2C86645C0491F9B45DACFC188113F', 'uBFEvpZ00HobdcEo'],
- ['40A757F83B2348A7B5F7F41790FDFFA02F72FC8FFD844BA6B28FD5DFD8CFC82F', 'NnemTiVU0UA5jVl0'],
- ['d6dac049cc944519806ab9a1b5e29ccfe3e74dabb4fa42598a45c35d20abdd28', '27b9bedf75ccA2eC']
- ]
- #define file locations
- addoncompat.get_revision()
- pluginpath = addoncompat.get_path()
- COOKIEFILE = os.path.join(pluginpath,'resources','cache','hulu-cookies.lwp')
- QUEUETOKEN = os.path.join(pluginpath,'resources','cache','token.xml')
- ADCACHE = os.path.join(pluginpath,'resources','cache','ad.xml')
- SMILCACHE = os.path.join(pluginpath,'resources','cache','smil.xml')
- WARNING = os.path.join(pluginpath,'resources','cache','warning')
- cachepath = os.path.join(pluginpath,'resources','cache')
- imagepath = os.path.join(pluginpath,'resources','images')
- hulu_fanart = os.path.join(pluginpath,'fanart.jpg')
- hulu_icon = os.path.join(imagepath,'icon.png')
- if os.path.isfile(WARNING):
- xbmcgui.Dialog().ok('Attention','This is Free Software.','If you paid for the Hulu plug-in then you have','been defrauded and should request a refund.',)
- os.remove(WARNING)
- """
- GET SETTINGS
- """
- settings={}
- handle = int(sys.argv[1])
- #settings Advanced
- settings['quality'] = addoncompat.get_setting("quality")
- settings['adquality'] = int(addoncompat.get_setting("adquality"))
- settings['prerollads'] = int(addoncompat.get_setting("prerollads"))
- settings['networkpreroll'] = addoncompat.get_setting("networkpreroll")
- settings['trailads'] = int(addoncompat.get_setting("trailads"))
- settings['adbreaks'] = int(addoncompat.get_setting("adbreaks"))
- settings['segmentvideos'] = addoncompat.get_setting("segmentvideos")
- #settings['swfverify'] = addoncompat.get_setting("swfverify")
- cdns = ['darwin-level3','darwin-limelight','darwin-edgecast']
- defualtcdn = int(addoncompat.get_setting("defaultcdn"))
- settings['defaultcdn'] = cdns[defualtcdn]
- #setting captions
- settings['enable_captions'] = addoncompat.get_setting("enable_captions")
- settings['queueremove'] = addoncompat.get_setting("queueremove")
- settings['proxy_enable'] = addoncompat.get_setting('us_proxy_enable')
- #per page settings
- page = ['25','50','100','250','500','1000','2000']
- perpage = int(addoncompat.get_setting("perpage"))
- settings['perpage'] = page[perpage]
- popperpage = int(addoncompat.get_setting("popperpage"))
- settings['popperpage'] = page[popperpage]
- allperpage = int(addoncompat.get_setting("allperpage" ))
- settings['allperpage'] = page[allperpage]
- searchperpage = int(addoncompat.get_setting("searchperpage" ))
- settings['searchperpage'] = page[searchperpage]
- settings['viewenable'] = addoncompat.get_setting("viewenable")
- settings['defaultview'] = addoncompat.get_setting("defaultview")
- settings['enablelibraryfolder'] = addoncompat.get_setting("enablelibraryfolder")
- settings['customlibraryfolder'] = addoncompat.get_setting("customlibraryfolder")
- settings['updatelibrary'] = addoncompat.get_setting("updatelibrary")
- settings['librarysuffix'] = addoncompat.get_setting("librarysuffix")
- settings['shownfo'] = addoncompat.get_setting("shownfo")
- settings['movienfo'] = addoncompat.get_setting("movienfo")
- settings['episodenfo'] = addoncompat.get_setting("episodenfo")
- #settings login
- settings['login_name'] = addoncompat.get_setting("login_name")
- settings['login_pass'] = addoncompat.get_setting("login_pass")
- settings['enable_login'] = addoncompat.get_setting("enable_login")
- settings['enable_plus'] = addoncompat.get_setting("enable_plus")
- #Token settings
- def setToken():
- xml = OpenFile(QUEUETOKEN)
- tree = ElementTree.XML(xml)
- settings['expiration'] = tree.findtext('token-expires-at')
- settings['usertoken'] = tree.findtext('token')
- settings['planid'] = tree.findtext('plid')
- settings['userid'] = tree.findtext('id')
- def checkToken():
- if os.path.isfile(QUEUETOKEN):
- setToken()
- expires = time.strptime(settings['expiration'], "%Y-%m-%dT%H:%M:%SZ")
- now = time.localtime()
- if now > expires:
- print 'Expired Token'
- login_queue()
- elif settings['enable_login'] == 'true':
- login_queue()
- if os.path.isfile(QUEUETOKEN):
- setToken()
- else:
- print 'HULU --> Login disabled'
- """
- Clean Non-Ascii characters from names for XBMC
- """
- def cleanNames(string):
- try:
- string = string.replace("'","").replace(unicode(u'\u201c'), '"').replace(unicode(u'\u201d'), '"').replace(unicode(u'\u2019'),'').replace(unicode(u'\u2026'),'...').replace(unicode(u'\u2018'),'').replace(unicode(u'\u2013'),'-')
- return string
- except:
- return string
- """
- ADD DIRECTORY
- """
- try:
- args.fanart
- except:
- args.fanart=''
- def addDirectory(name, url='', mode='default', thumb='', icon='', fanart='', plot='', genre='', showid='', season='', page = '1',perpage='',popular='false',updatelisting='false',cm=False):
- ok=True
- u = sys.argv[0]
- u += '?url="'+urllib.quote_plus(url)+'"'
- u += '&mode="'+urllib.quote_plus(mode)+'"'
- u += '&name="'+urllib.quote_plus(name)+'"'
- u += '&art=""'
- u += '&fanart=""'
- u += '&page="'+urllib.quote_plus(page)+'"'
- u += '&perpage="'+urllib.quote_plus(perpage)+'"'
- u += '&popular="'+urllib.quote_plus(popular)+'"'
- u += '&updatelisting="'+urllib.quote_plus(updatelisting)+'"'
- liz=xbmcgui.ListItem(name, iconImage=icon, thumbnailImage=icon)
- liz.setInfo( type="Video", infoLabels={ "Title":name, "Plot":cleanNames(plot), "Genre":genre})
- liz.setProperty('fanart_image',fanart)
- if cm:
- liz.addContextMenuItems( cm )#,replaceItems=True)
- ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
- return ok
- """
- READ PAGE
- """
- def getFEED( url , postdata=None , proxy = False):
- try:
- print 'HULU --> common :: getFEED :: url = '+url
- if proxy == True:
- us_proxy = 'http://' + addoncompat.get_setting('us_proxy') + ':' + addoncompat.get_setting('us_proxy_port')
- proxy_handler = urllib2.ProxyHandler({'http':us_proxy})
- if addoncompat.get_setting('us_proxy_pass') <> '' and addoncompat.get_setting('us_proxy_user') <> '':
- print 'Using authenticated proxy: ' + us_proxy
- password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
- password_mgr.add_password(None, us_proxy, addoncompat.get_setting('us_proxy_user'), addoncompat.get_setting('us_proxy_pass'))
- proxy_auth_handler = urllib2.ProxyBasicAuthHandler(password_mgr)
- opener = urllib2.build_opener(proxy_handler, proxy_auth_handler)
- else:
- print 'Using proxy: ' + us_proxy
- opener = urllib2.build_opener(proxy_handler)
- urllib2.install_opener(opener)
- if postdata == None:
- req = urllib2.Request(url)
- else:
- req = urllib2.Request(url,postdata)
- req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)')
- req.add_header('Referer', 'http://download.hulu.com/hulu10.html')
- #req.add_header('x-flash-version', '11,1,102,55')
- response = urllib2.urlopen(req)
- link=response.read()
- response.close()
- except urllib2.URLError, e:
- print 'Error reason: ', e
- heading = 'Error'
- message = e
- duration = 10000
- xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
- return False
- else:
- return link
- def postSTOP( type,content_id,position ):
- print 'HULU --> common :: postSTOP :: content_id = '+content_id
- opener = urllib2.build_opener()
- opener.addheaders = [('Referer', 'http://download.hulu.com/huludesktop.swf?ver=0.1.0'),
- ('x-flash-version', '11,1,102,55'),
- ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)')]
- url = 'http://www.hulu.com/pt/position'
- strposition = "%.2f" % position
- values = {'type':type,
- 'position':strposition,
- 'token':settings['usertoken'],
- 'content_id':content_id,
- 'device_name':'huludesktop'}
- data = urllib.urlencode(values)
- usock=opener.open(url,data)
- response=usock.read()
- usock.close()
- return response
- def SaveFile(path, data):
- file = open(path,'w')
- file.write(data)
- file.close()
- def OpenFile(path):
- file = open(path, 'r')
- contents=file.read()
- file.close()
- return contents
- def AES(key):
- return Rijndael(key, keySize=32, blockSize=16, padding=padWithPadLen())
- def AES_CBC(key):
- return CBC(blockCipherInstance=AES(key))
- def makeGUID():
- guid = ''
- for i in range(8):
- number = "%X" % (int( ( 1.0 + random.random() ) * 0x10000) | 0)
- guid += number[1:]
- return guid
- """
- Queue Token Login
- """
- def login_queue():
- if settings['login_name']=='' or settings['login_pass']=='':
- print "Hulu --> WARNING: Could not login. Please enter a username and password in settings"
- return False
- action = "authenticate"
- parameters = {'login' : settings['login_name'],
- 'password': settings['login_pass'],
- 'nonce' : NONCE()}
- data = postAPI(action,parameters,True)
- SaveFile(QUEUETOKEN, data)
- Notify('Success','User Queue Login Successful',4000)
- def Notify(heading,message,duration):
- xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
- def APIsignature(action,parameters):
- sorted_parameters = sorted(parameters.iteritems(), key=operator.itemgetter(0))
- paramsString = ''
- for item1, item2 in sorted_parameters:
- paramsString += str(item1) + str(item2)
- secret = "mTGPli7doNEpGfaVB9fquWfuAis"
- data = secret + action + paramsString
- try:
- import hashlib
- return hashlib.sha1(data).hexdigest()
- except:
- import sha
- return sha.new(data).hexdigest()
- def postAPI( action , parameters, secure):
- if secure == True:
- url = 'https://secure.'
- host = 'secure.hulu.com'
- elif secure == False:
- url = 'http://www.'
- host = 'www.hulu.com'
- url += 'hulu.com/api/1.0/'+action
- parameters['app'] = 'f8aa99ec5c28937cf3177087d149a96b5a5efeeb'
- parameters['sig'] = APIsignature(action,parameters)
- data = urllib.urlencode(parameters)
- headers = {'User-Agent':'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)',
- 'Host': host,
- 'Referer':'http://download.hulu.com/huludesktop.swf?ver=0.1.0'
- }
- req = urllib2.Request(url,data,headers)
- response = urllib2.urlopen(req)
- link=response.read()
- response.close()
- return link
- def NONCE():
- action = 'nonce'
- values = {}
- data = postAPI(action,values,True)
- return re.compile('<nonce>(.+?)</nonce>').findall(data)[0]
- def userSettings():
- action = 'user'
- values = {'token' : settings['usertoken'],
- 'operation' : 'config'}
- return postAPI(action , values, False)
- def viewcomplete():
- action = "event"
- parameters = {'event_type':'view_complete',
- 'token':settings['usertoken'],
- 'target_type':'video',
- 'id':args.videoid}
- postAPI(action,parameters,False)
- print "HULU --> Posted View Complete"
- def viewed(videoid):
- try:
- action = "event"
- parameters = {'event_type':'view',
- 'token':settings['usertoken'],
- 'target_type':'video',
- 'id':videoid}
- postAPI(action,parameters,False)
- print "HULU --> Posted view"
- except:
- print "HULU --> Post view failed"
- def queueEdit():
- values = {'token':settings['usertoken'],
- 'id':args.url}
- try:
- if args.mode == 'addqueue':
- values['operation'] = 'add'
- action = 'queue'
- data=postAPI(action,values,False)
- message = 'Added to Queue'
- elif args.mode == 'removequeue':
- values['operation'] = 'remove'
- action = 'queue'
- data=postAPI(action,values,False)
- message = 'Removed from Queue'
- elif args.mode == 'addsub':
- values['operation'] = 'add'
- values['type'] = 'episodes'
- action = 'subscription'
- data=postAPI(action,values,False)
- message = 'Added Subscription'
- elif args.mode == 'removesub':
- values['operation'] = 'remove'
- values['type'] = 'episodes'
- action = 'subscription'
- message = 'Removed Subscription'
- data=postAPI(action,values,False)
- elif args.mode == 'removehistory':
- values['operation'] = 'remove'
- action = 'history'
- data=postAPI(action,values,False)
- message = 'Removed from History'
- elif args.mode == 'vote':
- star = unicode(u'\u2605')
- rating = xbmcgui.Dialog().select('Vote for Video', [star, star+star, star+star+star, star+star+star+star, star+star+star+star+star])
- if rating!=-1:
- rating += 1
- values['target_type'] = 'video'
- values['rating'] = rating
- action = 'vote'
- data=postAPI(action,values,False)
- message = 'Vote Succeeded'
- else:
- return
- if 'ok' in data:
- heading = 'Success'
- duration = 3000
- else:
- heading = 'Failure'
- message = 'Operation Failed'
- duration = 4000
- Notify(heading,message,duration)
- except:
- Notify('Failure','Operation Failed',4000)
- #Do token settings
- checkToken()
- """
- Hulu+ Cookie Login
- NO LONGER USED
- """
- def login_cookie():
- #don't do anything if they don't have a password or username entered
- login_url = "https://secure.hulu.com/account/authenticate"
- if settings['login_name']=='' or settings['login_pass']=='':
- print "Hulu --> WARNING: Could not login. Please enter a username and password in settings"
- return False
- cj = cookielib.LWPCookieJar()
- if os.path.isfile(COOKIEFILE):
- cj.load(COOKIEFILE, ignore_discard=True, ignore_expires=True)
- opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
- opener.addheaders = [('Referer', 'http://hulu.com'),
- ('Content-Type', 'application/x-www-form-urlencoded'),
- ('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14'),
- ('Connection', 'keep-alive')]
- data =urllib.urlencode({"login":settings['login_name'],"password":settings['login_pass']})
- usock = opener.open(login_url, data)
- response = usock.read()
- usock.close()
- print 'HULU -- > These are the cookies we have received:'
- for index, cookie in enumerate(cj):
- print 'HULU--> '+str(index)+': '+str(cookie)
- print "HULU --> login_url response (we want 'ok=1'): " + response
- if response == 'ok=1':
- cj.save(COOKIEFILE, ignore_discard=True, ignore_expires=True)
- loggedIn = True
- heading = 'Success'
- message = 'Hulu Login Successful'
- duration = 1500
- xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
- else:
- loggedIn = False
- heading = 'Failure'
- message = 'Hulu Login Failed'
- duration = 1500
- xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
Add Comment
Please, Sign In to add comment