Guest User

common.py same directory as stream_hulu.py

a guest
Mar 17th, 2014
192
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.34 KB | None | 0 0
  1. import xbmcplugin
  2. import xbmc
  3. import xbmcgui
  4. import addoncompat
  5. import urllib
  6. import urllib2
  7. import sys
  8. import os
  9. import cookielib
  10. import operator
  11. import re
  12. import time
  13. import random
  14.  
  15.  
  16. from crypto.cipher.cbc import CBC
  17. from crypto.cipher.base import padWithPadLen
  18. from crypto.cipher.rijndael import Rijndael
  19.  
  20.  
  21. try:
  22. from xml.etree import ElementTree
  23. except:
  24. from elementtree import ElementTree
  25.  
  26. """
  27. PARSE ARGV
  28. """
  29.  
  30. class _Info:
  31. def __init__( self, *args, **kwargs ):
  32. self.__dict__.update( kwargs )
  33.  
  34. exec "args = _Info(%s)" % (urllib.unquote_plus(sys.argv[2][1:].replace("&", ", ").replace('"','\'').replace('%5C', '%5C%5C')), )
  35.  
  36.  
  37. """
  38. DEFINE URLS
  39. """
  40. BASE_MENU_URL = "http://m.hulu.com/menu/hd_main_menu?show_id=0&dp_id=huludesktop&package_id=2&page=1"
  41.  
  42. xmldeckeys = [
  43. ['4878B22E76379B55C962B18DDBC188D82299F8F52E3E698D0FAF29A40ED64B21', 'WA7hap7AGUkevuth'],
  44. ['246DB3463FC56FDBAD60148057CB9055A647C13C02C64A5ED4A68F81AE991BF5', 'vyf8PvpfXZPjc7B1'],
  45. ['8CE8829F908C2DFAB8B3407A551CB58EBC19B07F535651A37EBC30DEC33F76A2', 'O3r9EAcyEeWlm5yV'],
  46. ['852AEA267B737642F4AE37F5ADDF7BD93921B65FE0209E47217987468602F337', 'qZRiIfTjIGi3MuJA'],
  47. ['76A9FDA209D4C9DCDFDDD909623D1937F665D0270F4D3F5CA81AD2731996792F', 'd9af949851afde8c'],
  48. ['1F0FF021B7A04B96B4AB84CCFD7480DFA7A972C120554A25970F49B6BADD2F4F', 'tqo8cxuvpqc7irjw'],
  49. ['3484509D6B0B4816A6CFACB117A7F3C842268DF89FCC414F821B291B84B0CA71', 'SUxSFjNUavzKIWSh'],
  50. ['B7F67F4B985240FAB70FF1911FCBB48170F2C86645C0491F9B45DACFC188113F', 'uBFEvpZ00HobdcEo'],
  51. ['40A757F83B2348A7B5F7F41790FDFFA02F72FC8FFD844BA6B28FD5DFD8CFC82F', 'NnemTiVU0UA5jVl0'],
  52. ['d6dac049cc944519806ab9a1b5e29ccfe3e74dabb4fa42598a45c35d20abdd28', '27b9bedf75ccA2eC']
  53. ]
  54.  
  55. #define file locations
  56. addoncompat.get_revision()
  57. pluginpath = addoncompat.get_path()
  58.  
  59. COOKIEFILE = os.path.join(pluginpath,'resources','cache','hulu-cookies.lwp')
  60. QUEUETOKEN = os.path.join(pluginpath,'resources','cache','token.xml')
  61. ADCACHE = os.path.join(pluginpath,'resources','cache','ad.xml')
  62. SMILCACHE = os.path.join(pluginpath,'resources','cache','smil.xml')
  63. WARNING = os.path.join(pluginpath,'resources','cache','warning')
  64. cachepath = os.path.join(pluginpath,'resources','cache')
  65. imagepath = os.path.join(pluginpath,'resources','images')
  66. hulu_fanart = os.path.join(pluginpath,'fanart.jpg')
  67. hulu_icon = os.path.join(imagepath,'icon.png')
  68.  
  69.  
  70. if os.path.isfile(WARNING):
  71. 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.',)
  72. os.remove(WARNING)
  73. """
  74. GET SETTINGS
  75. """
  76.  
  77. settings={}
  78. handle = int(sys.argv[1])
  79.  
  80. #settings Advanced
  81. settings['quality'] = addoncompat.get_setting("quality")
  82. settings['adquality'] = int(addoncompat.get_setting("adquality"))
  83. settings['prerollads'] = int(addoncompat.get_setting("prerollads"))
  84. settings['networkpreroll'] = addoncompat.get_setting("networkpreroll")
  85. settings['trailads'] = int(addoncompat.get_setting("trailads"))
  86. settings['adbreaks'] = int(addoncompat.get_setting("adbreaks"))
  87. settings['segmentvideos'] = addoncompat.get_setting("segmentvideos")
  88. #settings['swfverify'] = addoncompat.get_setting("swfverify")
  89. cdns = ['darwin-level3','darwin-limelight','darwin-edgecast']
  90. defualtcdn = int(addoncompat.get_setting("defaultcdn"))
  91. settings['defaultcdn'] = cdns[defualtcdn]
  92. #setting captions
  93. settings['enable_captions'] = addoncompat.get_setting("enable_captions")
  94. settings['queueremove'] = addoncompat.get_setting("queueremove")
  95. settings['proxy_enable'] = addoncompat.get_setting('us_proxy_enable')
  96. #per page settings
  97. page = ['25','50','100','250','500','1000','2000']
  98. perpage = int(addoncompat.get_setting("perpage"))
  99. settings['perpage'] = page[perpage]
  100. popperpage = int(addoncompat.get_setting("popperpage"))
  101. settings['popperpage'] = page[popperpage]
  102. allperpage = int(addoncompat.get_setting("allperpage" ))
  103. settings['allperpage'] = page[allperpage]
  104. searchperpage = int(addoncompat.get_setting("searchperpage" ))
  105. settings['searchperpage'] = page[searchperpage]
  106.  
  107. settings['viewenable'] = addoncompat.get_setting("viewenable")
  108. settings['defaultview'] = addoncompat.get_setting("defaultview")
  109.  
  110. settings['enablelibraryfolder'] = addoncompat.get_setting("enablelibraryfolder")
  111. settings['customlibraryfolder'] = addoncompat.get_setting("customlibraryfolder")
  112. settings['updatelibrary'] = addoncompat.get_setting("updatelibrary")
  113. settings['librarysuffix'] = addoncompat.get_setting("librarysuffix")
  114. settings['shownfo'] = addoncompat.get_setting("shownfo")
  115. settings['movienfo'] = addoncompat.get_setting("movienfo")
  116. settings['episodenfo'] = addoncompat.get_setting("episodenfo")
  117.  
  118. #settings login
  119. settings['login_name'] = addoncompat.get_setting("login_name")
  120. settings['login_pass'] = addoncompat.get_setting("login_pass")
  121. settings['enable_login'] = addoncompat.get_setting("enable_login")
  122. settings['enable_plus'] = addoncompat.get_setting("enable_plus")
  123.  
  124. #Token settings
  125. def setToken():
  126. xml = OpenFile(QUEUETOKEN)
  127. tree = ElementTree.XML(xml)
  128. settings['expiration'] = tree.findtext('token-expires-at')
  129. settings['usertoken'] = tree.findtext('token')
  130. settings['planid'] = tree.findtext('plid')
  131. settings['userid'] = tree.findtext('id')
  132.  
  133. def checkToken():
  134. if os.path.isfile(QUEUETOKEN):
  135. setToken()
  136. expires = time.strptime(settings['expiration'], "%Y-%m-%dT%H:%M:%SZ")
  137. now = time.localtime()
  138. if now > expires:
  139. print 'Expired Token'
  140. login_queue()
  141. elif settings['enable_login'] == 'true':
  142. login_queue()
  143. if os.path.isfile(QUEUETOKEN):
  144. setToken()
  145. else:
  146. print 'HULU --> Login disabled'
  147.  
  148.  
  149.  
  150. """
  151. Clean Non-Ascii characters from names for XBMC
  152. """
  153.  
  154. def cleanNames(string):
  155. try:
  156. 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'),'-')
  157. return string
  158. except:
  159. return string
  160.  
  161.  
  162. """
  163. ADD DIRECTORY
  164. """
  165.  
  166. try:
  167. args.fanart
  168. except:
  169. args.fanart=''
  170.  
  171. def addDirectory(name, url='', mode='default', thumb='', icon='', fanart='', plot='', genre='', showid='', season='', page = '1',perpage='',popular='false',updatelisting='false',cm=False):
  172. ok=True
  173. u = sys.argv[0]
  174. u += '?url="'+urllib.quote_plus(url)+'"'
  175. u += '&mode="'+urllib.quote_plus(mode)+'"'
  176. u += '&name="'+urllib.quote_plus(name)+'"'
  177. u += '&art=""'
  178. u += '&fanart=""'
  179. u += '&page="'+urllib.quote_plus(page)+'"'
  180. u += '&perpage="'+urllib.quote_plus(perpage)+'"'
  181. u += '&popular="'+urllib.quote_plus(popular)+'"'
  182. u += '&updatelisting="'+urllib.quote_plus(updatelisting)+'"'
  183. liz=xbmcgui.ListItem(name, iconImage=icon, thumbnailImage=icon)
  184. liz.setInfo( type="Video", infoLabels={ "Title":name, "Plot":cleanNames(plot), "Genre":genre})
  185. liz.setProperty('fanart_image',fanart)
  186. if cm:
  187. liz.addContextMenuItems( cm )#,replaceItems=True)
  188. ok=xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
  189. return ok
  190.  
  191. """
  192. READ PAGE
  193. """
  194.  
  195. def getFEED( url , postdata=None , proxy = False):
  196. try:
  197. print 'HULU --> common :: getFEED :: url = '+url
  198. if proxy == True:
  199. us_proxy = 'http://' + addoncompat.get_setting('us_proxy') + ':' + addoncompat.get_setting('us_proxy_port')
  200. proxy_handler = urllib2.ProxyHandler({'http':us_proxy})
  201. if addoncompat.get_setting('us_proxy_pass') <> '' and addoncompat.get_setting('us_proxy_user') <> '':
  202. print 'Using authenticated proxy: ' + us_proxy
  203. password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
  204. password_mgr.add_password(None, us_proxy, addoncompat.get_setting('us_proxy_user'), addoncompat.get_setting('us_proxy_pass'))
  205. proxy_auth_handler = urllib2.ProxyBasicAuthHandler(password_mgr)
  206. opener = urllib2.build_opener(proxy_handler, proxy_auth_handler)
  207. else:
  208. print 'Using proxy: ' + us_proxy
  209. opener = urllib2.build_opener(proxy_handler)
  210. urllib2.install_opener(opener)
  211. if postdata == None:
  212. req = urllib2.Request(url)
  213. else:
  214. req = urllib2.Request(url,postdata)
  215. req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)')
  216. req.add_header('Referer', 'http://download.hulu.com/hulu10.html')
  217. #req.add_header('x-flash-version', '11,1,102,55')
  218. response = urllib2.urlopen(req)
  219. link=response.read()
  220. response.close()
  221.  
  222. except urllib2.URLError, e:
  223. print 'Error reason: ', e
  224. heading = 'Error'
  225. message = e
  226. duration = 10000
  227. xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
  228. return False
  229. else:
  230. return link
  231.  
  232. def postSTOP( type,content_id,position ):
  233. print 'HULU --> common :: postSTOP :: content_id = '+content_id
  234. opener = urllib2.build_opener()
  235. opener.addheaders = [('Referer', 'http://download.hulu.com/huludesktop.swf?ver=0.1.0'),
  236. ('x-flash-version', '11,1,102,55'),
  237. ('User-Agent', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)')]
  238. url = 'http://www.hulu.com/pt/position'
  239. strposition = "%.2f" % position
  240. values = {'type':type,
  241. 'position':strposition,
  242. 'token':settings['usertoken'],
  243. 'content_id':content_id,
  244. 'device_name':'huludesktop'}
  245. data = urllib.urlencode(values)
  246. usock=opener.open(url,data)
  247. response=usock.read()
  248. usock.close()
  249. return response
  250.  
  251. def SaveFile(path, data):
  252. file = open(path,'w')
  253. file.write(data)
  254. file.close()
  255.  
  256. def OpenFile(path):
  257. file = open(path, 'r')
  258. contents=file.read()
  259. file.close()
  260. return contents
  261.  
  262. def AES(key):
  263. return Rijndael(key, keySize=32, blockSize=16, padding=padWithPadLen())
  264.  
  265. def AES_CBC(key):
  266. return CBC(blockCipherInstance=AES(key))
  267.  
  268. def makeGUID():
  269. guid = ''
  270. for i in range(8):
  271. number = "%X" % (int( ( 1.0 + random.random() ) * 0x10000) | 0)
  272. guid += number[1:]
  273. return guid
  274.  
  275. """
  276. Queue Token Login
  277. """
  278. def login_queue():
  279. if settings['login_name']=='' or settings['login_pass']=='':
  280. print "Hulu --> WARNING: Could not login. Please enter a username and password in settings"
  281. return False
  282. action = "authenticate"
  283. parameters = {'login' : settings['login_name'],
  284. 'password': settings['login_pass'],
  285. 'nonce' : NONCE()}
  286. data = postAPI(action,parameters,True)
  287. SaveFile(QUEUETOKEN, data)
  288. Notify('Success','User Queue Login Successful',4000)
  289.  
  290. def Notify(heading,message,duration):
  291. xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
  292.  
  293. def APIsignature(action,parameters):
  294. sorted_parameters = sorted(parameters.iteritems(), key=operator.itemgetter(0))
  295. paramsString = ''
  296. for item1, item2 in sorted_parameters:
  297. paramsString += str(item1) + str(item2)
  298. secret = "mTGPli7doNEpGfaVB9fquWfuAis"
  299. data = secret + action + paramsString
  300. try:
  301. import hashlib
  302. return hashlib.sha1(data).hexdigest()
  303. except:
  304. import sha
  305. return sha.new(data).hexdigest()
  306.  
  307. def postAPI( action , parameters, secure):
  308. if secure == True:
  309. url = 'https://secure.'
  310. host = 'secure.hulu.com'
  311. elif secure == False:
  312. url = 'http://www.'
  313. host = 'www.hulu.com'
  314. url += 'hulu.com/api/1.0/'+action
  315. parameters['app'] = 'f8aa99ec5c28937cf3177087d149a96b5a5efeeb'
  316. parameters['sig'] = APIsignature(action,parameters)
  317. data = urllib.urlencode(parameters)
  318. headers = {'User-Agent':'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)',
  319. 'Host': host,
  320. 'Referer':'http://download.hulu.com/huludesktop.swf?ver=0.1.0'
  321. }
  322. req = urllib2.Request(url,data,headers)
  323. response = urllib2.urlopen(req)
  324. link=response.read()
  325. response.close()
  326. return link
  327.  
  328. def NONCE():
  329. action = 'nonce'
  330. values = {}
  331. data = postAPI(action,values,True)
  332. return re.compile('<nonce>(.+?)</nonce>').findall(data)[0]
  333.  
  334. def userSettings():
  335. action = 'user'
  336. values = {'token' : settings['usertoken'],
  337. 'operation' : 'config'}
  338. return postAPI(action , values, False)
  339.  
  340. def viewcomplete():
  341. action = "event"
  342. parameters = {'event_type':'view_complete',
  343. 'token':settings['usertoken'],
  344. 'target_type':'video',
  345. 'id':args.videoid}
  346. postAPI(action,parameters,False)
  347. print "HULU --> Posted View Complete"
  348.  
  349. def viewed(videoid):
  350. try:
  351. action = "event"
  352. parameters = {'event_type':'view',
  353. 'token':settings['usertoken'],
  354. 'target_type':'video',
  355. 'id':videoid}
  356. postAPI(action,parameters,False)
  357. print "HULU --> Posted view"
  358. except:
  359. print "HULU --> Post view failed"
  360.  
  361. def queueEdit():
  362. values = {'token':settings['usertoken'],
  363. 'id':args.url}
  364. try:
  365. if args.mode == 'addqueue':
  366. values['operation'] = 'add'
  367. action = 'queue'
  368. data=postAPI(action,values,False)
  369. message = 'Added to Queue'
  370. elif args.mode == 'removequeue':
  371. values['operation'] = 'remove'
  372. action = 'queue'
  373. data=postAPI(action,values,False)
  374. message = 'Removed from Queue'
  375. elif args.mode == 'addsub':
  376. values['operation'] = 'add'
  377. values['type'] = 'episodes'
  378. action = 'subscription'
  379. data=postAPI(action,values,False)
  380. message = 'Added Subscription'
  381. elif args.mode == 'removesub':
  382. values['operation'] = 'remove'
  383. values['type'] = 'episodes'
  384. action = 'subscription'
  385. message = 'Removed Subscription'
  386. data=postAPI(action,values,False)
  387. elif args.mode == 'removehistory':
  388. values['operation'] = 'remove'
  389. action = 'history'
  390. data=postAPI(action,values,False)
  391. message = 'Removed from History'
  392. elif args.mode == 'vote':
  393. star = unicode(u'\u2605')
  394. rating = xbmcgui.Dialog().select('Vote for Video', [star, star+star, star+star+star, star+star+star+star, star+star+star+star+star])
  395. if rating!=-1:
  396. rating += 1
  397. values['target_type'] = 'video'
  398. values['rating'] = rating
  399. action = 'vote'
  400. data=postAPI(action,values,False)
  401. message = 'Vote Succeeded'
  402. else:
  403. return
  404. if 'ok' in data:
  405. heading = 'Success'
  406. duration = 3000
  407. else:
  408. heading = 'Failure'
  409. message = 'Operation Failed'
  410. duration = 4000
  411. Notify(heading,message,duration)
  412. except:
  413. Notify('Failure','Operation Failed',4000)
  414.  
  415.  
  416. #Do token settings
  417. checkToken()
  418.  
  419.  
  420.  
  421.  
  422.  
  423. """
  424. Hulu+ Cookie Login
  425. NO LONGER USED
  426. """
  427.  
  428. def login_cookie():
  429. #don't do anything if they don't have a password or username entered
  430. login_url = "https://secure.hulu.com/account/authenticate"
  431. if settings['login_name']=='' or settings['login_pass']=='':
  432. print "Hulu --> WARNING: Could not login. Please enter a username and password in settings"
  433. return False
  434.  
  435. cj = cookielib.LWPCookieJar()
  436. if os.path.isfile(COOKIEFILE):
  437. cj.load(COOKIEFILE, ignore_discard=True, ignore_expires=True)
  438.  
  439. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
  440. opener.addheaders = [('Referer', 'http://hulu.com'),
  441. ('Content-Type', 'application/x-www-form-urlencoded'),
  442. ('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'),
  443. ('Connection', 'keep-alive')]
  444. data =urllib.urlencode({"login":settings['login_name'],"password":settings['login_pass']})
  445. usock = opener.open(login_url, data)
  446. response = usock.read()
  447. usock.close()
  448.  
  449. print 'HULU -- > These are the cookies we have received:'
  450. for index, cookie in enumerate(cj):
  451. print 'HULU--> '+str(index)+': '+str(cookie)
  452.  
  453. print "HULU --> login_url response (we want 'ok=1'): " + response
  454. if response == 'ok=1':
  455. cj.save(COOKIEFILE, ignore_discard=True, ignore_expires=True)
  456. loggedIn = True
  457. heading = 'Success'
  458. message = 'Hulu Login Successful'
  459. duration = 1500
  460. xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
  461. else:
  462. loggedIn = False
  463. heading = 'Failure'
  464. message = 'Hulu Login Failed'
  465. duration = 1500
  466. xbmc.executebuiltin('XBMC.Notification("%s", "%s", %s)' % ( heading, message, duration) )
Add Comment
Please, Sign In to add comment