Advertisement
Guest User

Untitled

a guest
Sep 27th, 2015
2,622
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 55.21 KB | None | 0 0
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import urllib
  4. import urllib2
  5. import socket
  6. import cookielib
  7. import sys
  8. import re
  9. import os
  10. import json
  11. import time
  12. import shutil
  13. import subprocess
  14. import xbmcplugin
  15. import xbmcgui
  16. import xbmcaddon
  17. import xbmcvfs
  18.  
  19.  
  20. socket.setdefaulttimeout(30)
  21. pluginhandle = int(sys.argv[1])
  22. addon = xbmcaddon.Addon()
  23. addonID = addon.getAddonInfo('id')
  24. cj = cookielib.MozillaCookieJar()
  25. urlMain = "http://www.netflix.com"
  26. osWin = xbmc.getCondVisibility('system.platform.windows')
  27. osLinux = xbmc.getCondVisibility('system.platform.linux')
  28. osOsx = xbmc.getCondVisibility('system.platform.osx')
  29. addonDir = xbmc.translatePath(addon.getAddonInfo('path'))
  30. defaultFanart = os.path.join(addonDir ,'fanart.png')
  31. addonUserDataFolder = xbmc.translatePath("special://profile/addon_data/"+addonID)
  32. icon = xbmc.translatePath('special://home/addons/'+addonID+'/icon.png')
  33. utilityPath = xbmc.translatePath('special://home/addons/'+addonID+'/resources/NetfliXBMC_Utility.exe')
  34. sendKeysPath = xbmc.translatePath('special://home/addons/'+addonID+'/resources/NetfliXBMC_SendKeys.exe')
  35. fakeVidPath = xbmc.translatePath('special://home/addons/'+addonID+'/resources/fakeVid.mp4')
  36. downloadScript = xbmc.translatePath('special://home/addons/'+addonID+'/download.py')
  37. searchHistoryFolder = os.path.join(addonUserDataFolder, "history")
  38. cacheFolder = os.path.join(addonUserDataFolder, "cache")
  39. cacheFolderCoversTMDB = os.path.join(cacheFolder, "covers")
  40. cacheFolderFanartTMDB = os.path.join(cacheFolder, "fanart")
  41. libraryFolder = xbmc.translatePath(addon.getSetting("libraryPath"))
  42. libraryFolderMovies = os.path.join(libraryFolder, "Movies")
  43. libraryFolderTV = os.path.join(libraryFolder, "TV")
  44. cookieFile = xbmc.translatePath("special://profile/addon_data/"+addonID+"/cookies")
  45. authIDFile = xbmc.translatePath("special://profile/addon_data/"+addonID+"/authID")
  46. dontUseKiosk = addon.getSetting("dontUseKiosk") == "true"
  47. browseTvShows = addon.getSetting("browseTvShows") == "true"
  48. singleProfile = addon.getSetting("singleProfile") == "true"
  49. showProfiles = addon.getSetting("showProfiles") == "true"
  50. forceView = addon.getSetting("forceView") == "true"
  51. useUtility = addon.getSetting("useUtility") == "true"
  52. remoteControl = addon.getSetting("remoteControl") == "true"
  53. updateDB = addon.getSetting("updateDB") == "true"
  54. useTMDb = addon.getSetting("useTMDb") == "true"
  55. username = addon.getSetting("username")
  56. password = addon.getSetting("password")
  57. viewIdVideos = addon.getSetting("viewIdVideos")
  58. viewIdEpisodes = addon.getSetting("viewIdEpisodesNew")
  59. viewIdActivity = addon.getSetting("viewIdActivity")
  60. winBrowser = int(addon.getSetting("winBrowserNew"))
  61. language = addon.getSetting("language")
  62. auth = addon.getSetting("auth")
  63. if len(language.split("-"))>1:
  64.     country = language.split("-")[1]
  65.  
  66. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
  67. userAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:32.0) Gecko/20100101 Firefox/32.0"
  68. opener.addheaders = [('User-agent', userAgent)]
  69.  
  70. if not os.path.isdir(addonUserDataFolder):
  71.     os.mkdir(addonUserDataFolder)
  72. if not os.path.isdir(cacheFolder):
  73.     os.mkdir(cacheFolder)
  74. if not os.path.isdir(cacheFolderCoversTMDB):
  75.     os.mkdir(cacheFolderCoversTMDB)
  76. if not os.path.isdir(cacheFolderFanartTMDB):
  77.     os.mkdir(cacheFolderFanartTMDB)
  78. if not os.path.isdir(libraryFolder):
  79.     xbmcvfs.mkdir(libraryFolder)
  80. if not os.path.isdir(libraryFolderMovies):
  81.     xbmcvfs.mkdir(libraryFolderMovies)
  82. if not os.path.isdir(libraryFolderTV):
  83.     xbmcvfs.mkdir(libraryFolderTV)
  84. if os.path.exists(cookieFile):
  85.     cj.load(cookieFile)
  86.  
  87. # TODO: finish authID caching so the REST API can be called directly
  88. # without going through a full page load
  89. class AuthID:
  90.     def __init__(self, filename):
  91.         self.filename = filename
  92.         self.ts = None
  93.         self.value = None
  94.    
  95.     def isExpired(self):
  96.         if self.ts == None:
  97.             return true
  98.    
  99.     def load(self):
  100.         with open(filename) as f:
  101.             self.ts = int(f.readline().strip())
  102.             self.value = f.readline().strip()
  103.    
  104.     def save(self):
  105.         with open(filename, "w") as f:
  106.             f.write(str(self.ts) + "\n")
  107.             f.write(self.value + "\n")
  108.  
  109. authID = AuthID(authIDFile)
  110. if os.path.exists(authIDFile):
  111.     authID.load()
  112.  
  113. while (username == "" or password == ""):
  114.     addon.openSettings()
  115.     username = addon.getSetting("username")
  116.     password = addon.getSetting("password")
  117.  
  118. if not addon.getSetting("html5MessageShown"):
  119.     dialog = xbmcgui.Dialog()
  120.     ok = dialog.ok('IMPORTANT!', 'NetfliXBMC >=1.3.0 only supports the new Netflix HTML5 User Interface! The only browsers working with HTML5 DRM playback for now are Chrome>=37 (Win/OSX/Linux) and IExplorer>=11 (Win8.1 only). Make sure you have the latest version installed and check your Netflix settings. Using Silverlight may still partially work, but its not supported anymore. The HTML5 Player is also much faster, supports 1080p and gives you a smoother playback (especially on Linux). See forum.xbmc.org for more info...')
  121.     addon.setSetting("html5MessageShown", "true")
  122.  
  123.    
  124. def index():
  125.     #if login():
  126.     addDir(translation(30011), "", 'main', "", "movie")
  127.     addDir(translation(30012), "", 'main', "", "tv")
  128.     addDir(translation(30143), "", 'wiHome', "", "both")
  129.     xbmcplugin.endOfDirectory(pluginhandle)
  130.  
  131.  
  132. def main(type):
  133.     print "Main"
  134.     xbmcplugin.setContent(pluginhandle, "movies")
  135.     addDir(translation(30002), urlMain+"/browse/my-list", 'myList', "", type)
  136.     addDir(translation(30010), "", 'listViewingActivity', "", type)
  137.     addDir(translation(30003), urlMain+"/browse/new-arrivals", 'newArrivals', "", type)
  138.     if type=="tv":
  139.         addDir(translation(30005), urlMain+"/browse/genre/83", 'listFiltered', "", type)
  140.         addDir(translation(30007), "", 'listTvGenres', "", type)
  141.     else:
  142.         addDir(translation(30007), urlMain + "/browse", 'listMovieGenres', "", type)
  143.     addDir(translation(30008), "", 'search', "", type)
  144.     xbmcplugin.endOfDirectory(pluginhandle)
  145.  
  146.  
  147. def wiHome(type):
  148.     if not singleProfile:
  149.         setProfile()
  150.     content = opener.open(urlMain+"/WiHome").read()
  151.     match1 = re.compile('<div class="mrow(.+?)"><div class="hd clearfix"><h3> (.+?)</h3></div><div class="bd clearfix"><div class="slider triangleBtns " id="(.+?)"', re.DOTALL).findall(content)
  152.     match2 = re.compile('class="hd clearfix"><h3><a href="(.+?)">(.+?)<', re.DOTALL).findall(content)
  153.     for temp, title, sliderID in match1:
  154.         if not "hide-completely" in temp:
  155.             addDir(title.strip(), sliderID, 'listSliderVideos', "", type)
  156.     for url, title in match2:
  157.         if "WiAltGenre" in url or "WiSimilarsByViewType" in url or "WiRecentAdditionsGallery" in url:
  158.             addDir(title.strip(), url, 'listVideos', "", type)
  159.     xbmcplugin.endOfDirectory(pluginhandle)
  160.  
  161. PAGE_SIZE = 100
  162.  
  163. def myList(url, type):
  164.     (apidata, data) = getNetflixPage("/browse/my-list")
  165.     addVideos(data["videos"], "myList", type, 0, 9999999)
  166.  
  167. def addVideos(vdict, op, type, startIndex, pageSize):
  168.     xbmcplugin.setContent(pluginhandle, "movies")
  169.     n = 0
  170.     for videoId in vdict.keys():
  171.         if videoId == "size" or videoId == "$size":
  172.             continue
  173.         n = n + 1
  174.         print "VideoID: " + videoId
  175.         vdata = vdict[videoId]
  176.         if type == "tv" and vdata["summary"]["type"] == "show":
  177.             listVideoFromJson(videoId, vdata, type, "listSeasons")
  178.         elif type == "movie" and vdata["summary"]["type"] == "movie":
  179.             listVideoFromJson(videoId, vdata, type, "playVideo")
  180.         elif type == "both":
  181.             if vdata["summary"]["type"] == "show":
  182.                 listVideoFromJson(videoId, vdata, type, "listSeasons")
  183.             else:
  184.                 listVideoFromJson(videoId, vdata, type, "playVideo")
  185.            
  186.     if n == pageSize:
  187.         nextFrom = startIndex + pageSize
  188.         newUrl = re.sub("&from=[0-9]+", "", url) + "&from=" + str(nextFrom)
  189.         addDir(translation(30001), newUrl, op, "", type)
  190.     if op == "newArrivals" or op == "listFiltered" or op == "myList":
  191.         xbmc.executebuiltin('Container.SetViewMode(500)')
  192.     else:
  193.         xbmc.executebuiltin('Container.SetViewMode(504)')
  194.     xbmcplugin.endOfDirectory(pluginhandle)
  195.  
  196. def newArrivals(url, type):
  197.     xbmcplugin.setContent(pluginhandle, "movies")
  198.     (apidata, data) = getNetflixPage("/browse/new-arrivals")
  199.     startIndex = getStartIndex(url)
  200.     rid = getNewReleasesId(data)
  201.     rid = rid.replace("SLW32-", "WWW-")
  202.     data2 = getNetflixAjaxData(apidata, makeListsRequest(apidata, rid, startIndex, PAGE_SIZE))
  203.     print "New arrivals: " + str(data2)
  204.     addVideos(data2["value"]["videos"], "newArrivals", type, startIndex, PAGE_SIZE)
  205.  
  206. def listFiltered(url, type):
  207.     (apidata, data) = getNetflixPage(url)
  208.     gid = getGenreId(url)
  209.     startIndex = getStartIndex(url)
  210.     data2 = getNetflixAjaxData(apidata, makeFilteredRequest(apidata, gid, startIndex, PAGE_SIZE))
  211.     addVideos(data2["value"]["videos"], "listFiltered", type, startIndex, PAGE_SIZE)
  212.  
  213. def makeFilteredRequest(apidata, gid, startIndex, pageSize):
  214.     authURL = apidata["contextData"]["userInfo"]["data"]["authURL"]
  215.     sgid = str(gid)
  216.     sfrom = str(startIndex)
  217.     sto = str(startIndex + pageSize - 1)
  218.     return '{"paths":[["genres",%s,["id","length","name","trackIds","requestId"]],["genres",%s,"su",{"from":%s,"to":%s},["summary","title","info"]],["genres",%s,"su",{"from":%s,"to":%s},"boxarts","_342x192","jpg"],["genres",%s,"su","requestId"]],"authURL":"%s"}' % (sgid, sgid, sfrom, sto, sgid, sfrom, sto, sgid, authURL)
  219.  
  220. def getNetflixAjaxData(apidata, postdata):
  221.     url = getNetflixAjaxUrl(apidata)
  222.     print "POST: " + postdata
  223.     content = opener.open(url, postdata).read()
  224.     return json.loads(content)
  225.    
  226. def getNetflixAjaxUrl(apidata):
  227.     apiId = apidata["contextData"]["services"]["data"]["api"]["path"]
  228.     return "http://www.netflix.com/" + "/".join(apiId) + "/pathEvaluator?withSize=true&materialize=true&model=harris&fallbackEsn=WWW"
  229.    
  230. def makeListsRequest(apidata, rid, startIndex, pageSize):
  231.     authURL = apidata["contextData"]["userInfo"]["data"]["authURL"]
  232.     return '{"paths":[["lists","%s",{"from":%s,"to":%s},["summary","title","releaseYear","userRating","runtime","synopsis"]],["lists","%s",{"from":1,"to":100},"boxarts","_342x192","jpg"]],"authURL":"%s"}' % (rid, str(startIndex), str(startIndex + pageSize - 1), rid, authURL)
  233.  
  234. def getNetflixPage(path):
  235.     print "Get netflix page " + path
  236.     if not singleProfile:
  237.         setProfile()
  238.     url = "http://www.netflix.com" + path
  239.     print "Url: " + url
  240.     content = opener.open(url).read()
  241.     if not 'id="page-LOGIN"' in content:
  242.         if singleProfile and '"showGate":{"data":true' in content:
  243.             print "Got profiles page. Reloading..."
  244.             #forceChooseProfile()
  245.             content = opener.open(url).read()
  246.             #print "Content: " + content
  247.         content = content.replace("\\t","").replace("\\n", "").replace("\\", "")
  248.         apiInfo = getJson(content, "netflix.reactContext")
  249.         data = getJson(content, "netflix.falkorCache")
  250.         return (apiInfo, data)
  251.     else:
  252.         deleteCookies()
  253.         xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30127))+',15000,'+icon+')')
  254.  
  255. def getGenreId(url):
  256.     print "GetGenreId url: " + url
  257.     gre = re.compile("/browse/genre/([0-9]+)", re.DOTALL).findall(url)
  258.     if gre:
  259.         return gre[0]
  260.     return None
  261.  
  262. def getStartIndex(url):
  263.     pagerRe = re.compile('&from=(.+?)&', re.DOTALL).findall(url)
  264.     startIndex = 0
  265.     if pagerRe:
  266.         startIndex = int(pagerRe[1])
  267.     return startIndex
  268.  
  269. def getJson(content, varName):
  270.     ix = content.find(varName + " = ")
  271.     ix2 = content.find("</script>", ix)
  272.     js = content[ix + len(varName) + 3:ix2]
  273.     js = js[:js.rfind(";")]
  274.     if js.find('"focalPoint":"{"') >= 0:
  275.         #the broken kind. Hey, netflix, use a proper json encoder
  276.         js = re.sub('"focalPoint":"\{[^{]+\}",', "", js)
  277.         print "Had to fix json"
  278.     #print "json: " + js
  279.     try:
  280.         return json.loads(js)
  281.     except Exception as ex:
  282.         print "Could not parse:\n--------\n" + js + "\n---------\n"
  283.         raise ex
  284.  
  285.  
  286. def getNewReleasesId(data):
  287.     print str(data.keys())
  288.     for key in data["lists"].keys():
  289.         if data["lists"][key]["displayName"]["value"] == "New Releases":
  290.             return key
  291.     return None
  292.  
  293. def listSliderVideos(sliderID, type):
  294.     pDialog = xbmcgui.DialogProgress()
  295.     pDialog.create('NetfliXBMC', translation(30142)+"...")
  296.     if not singleProfile:
  297.         setProfile()
  298.     xbmcplugin.setContent(pluginhandle, "movies")
  299.     content = opener.open(urlMain+"/WiHome").read()
  300.     if not 'id="page-LOGIN"' in content:
  301.         if singleProfile and 'id="page-ProfilesGate"' in content:
  302.             forceChooseProfile()
  303.         else:
  304.             content = content.replace("\\t","").replace("\\n", "").replace("\\", "")
  305.             contentMain = content
  306.             content = content[content.find('id="'+sliderID+'"'):]
  307.             content = content[:content.find('class="ft"')]
  308.             match = re.compile('<span id="dbs(.+?)_', re.DOTALL).findall(content)
  309.             i = 1
  310.             for videoID in match:
  311.                 listVideo(videoID, "", "", False, False, type)
  312.                 i+=1
  313.             spl = contentMain.split('"remainderHTML":')
  314.             for i in range(1, len(spl), 1):
  315.                 entry = spl[i]
  316.                 entry = entry[:entry.find('"rowId":')]
  317.                 if '"domId":"'+sliderID+'"' in entry:
  318.                     match = re.compile('<span id="dbs(.+?)_', re.DOTALL).findall(entry)
  319.                     i = 1
  320.                     for videoID in match:
  321.                         pDialog.update(i*100/(len(match)+10), translation(30142)+"...")
  322.                         listVideo(videoID, "", "", False, False, type)
  323.                         i+=1
  324.             if forceView:
  325.                 xbmc.executebuiltin('Container.SetViewMode('+viewIdVideos+')')
  326.             xbmcplugin.endOfDirectory(pluginhandle)
  327.     else:
  328.         deleteCookies()
  329.         xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30127))+',15000,'+icon+')')
  330.  
  331.  
  332. def listSearchVideos(url, type):
  333.     pDialog = xbmcgui.DialogProgress()
  334.     pDialog.create('NetfliXBMC', translation(30142)+"...")
  335.     if not singleProfile:
  336.         setProfile()
  337.     xbmcplugin.setContent(pluginhandle, "movies")
  338.     content = opener.open(url).read()
  339.     content = json.loads(content)
  340.     i = 1
  341.     if "galleryVideos" in content:
  342.         for item in content["galleryVideos"]["items"]:
  343.             pDialog.update(i*100/len(content["galleryVideos"]["items"]), translation(30142)+"...")
  344.             listVideo(str(item["id"]), "", "", False, False, type)
  345.             i+=1
  346.         if forceView:
  347.             xbmc.executebuiltin('Container.SetViewMode('+viewIdVideos+')')
  348.         xbmcplugin.endOfDirectory(pluginhandle)
  349.     else:
  350.         xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30146))+',5000,'+icon+')')
  351.  
  352. def listVideoFromJson(videoID, vdata, type, action):
  353.     print "VDATA: " + str(vdata)
  354.     if isinstance(vdata["title"], dict):
  355.         title = vdata["title"]["value"]
  356.     else:
  357.         title = vdata["title"]
  358.     synopsis = ""
  359.     if "info" in vdata and "narrativeSynopsis" in vdata["info"]:
  360.         synopsis = vdata["info"]["narrativeSynopsis"].encode("utf-8")
  361.     if "synopsis" in vdata:
  362.         synopsis = vdata["synopsis"].encode("utf-8")
  363.     icon = ""
  364.     if "boxarts" in vdata:
  365.         for k in vdata["boxarts"].keys():
  366.             if len(k) > 0 and k[0] == "_":
  367.                 if "jpg" in vdata["boxarts"][k]:
  368.                     icon = vdata["boxarts"][k]["jpg"]["url"]
  369.                 elif "webp" in vdata["boxarts"][k]:
  370.                     icon = vdata["boxarts"][k]["webp"]["url"]
  371.     year = ""
  372.     if "releaseYear" in vdata:
  373.         year = str(vdata["releaseYear"])
  374.     duration = ""
  375.     if "runtime" in vdata:
  376.         duration = str(vdata["runtime"]["value"])
  377.         if duration == None:
  378.             duration = ""
  379.     rating = ""
  380.     if "userRating" in vdata:
  381.         rating = str(vdata["userRating"]["predicted"])
  382.     if action == "listSeasons":
  383.         #addDir(title.encode("utf-8"), urlMain+"/title/" + videoID, "listSeasons", icon, type)
  384.         #addVideoDirR(name, url, mode, iconimage, videoType="", desc="", duration="", year="", mpaa="", director="", genre="", rating=""):
  385.         addVideoDir(title.encode("utf-8"), (urlMain+"/title/" + videoID).encode("utf-8"), "listSeasons", icon, type,
  386.             synopsis, duration, year, "", "", "", rating)
  387.     else:
  388.         videoType = "movie"
  389.         if type == "tv":
  390.             videoType = "tvshow"
  391.         addVideoDirR(title.encode("utf-8"), videoID.encode("utf-8"), "playVideoMain", icon, videoType,
  392.             synopsis, duration, year, "", "", "", rating)
  393.     return True
  394.  
  395. def listVideo(videoID, title, thumbUrl, tvshowIsEpisode, hideMovies, type):
  396.     videoDetails = getVideoInfo(videoID)
  397.     match = re.compile('<span class="title.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  398.     if not title:
  399.         title = match[0].strip()
  400.     year = ""
  401.     match = re.compile('<span class="year.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  402.     if match:
  403.         year = match[0]
  404.     if not thumbUrl:
  405.         match = re.compile('src="(.+?)"', re.DOTALL).findall(videoDetails)
  406.         thumbUrl = match[0].replace("/webp/","/images/").replace(".webp",".jpg")
  407.     match = re.compile('<span class="mpaaRating.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  408.     mpaa = ""
  409.     if match:
  410.         mpaa = match[0]
  411.     match = re.compile('<span class="duration.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  412.     duration = ""
  413.     if match:
  414.         duration = match[0].lower()
  415.     if duration.split(' ')[-1] in ["minutes", "minutos", "minuter", "minutter", "minuuttia", "minuten"]:
  416.         videoType = "movie"
  417.         videoTypeTemp = videoType
  418.         duration = duration.split(" ")[0]
  419.     else:
  420.         videoTypeTemp = "tv"
  421.         if tvshowIsEpisode:
  422.             videoType = "episode"
  423.             year = ""
  424.         else:
  425.             videoType = "tvshow"
  426.         duration = ""
  427.     if useTMDb:
  428.         yearTemp = year
  429.         titleTemp = title
  430.         if " - " in titleTemp:
  431.             titleTemp = titleTemp[titleTemp.find(" - ")+3:]
  432.         if ": " in titleTemp:
  433.             titleTemp = titleTemp[:titleTemp.find(": ")]
  434.         if "-" in yearTemp:
  435.             yearTemp = yearTemp.split("-")[0]
  436.         filename = (''.join(c for c in unicode(videoID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  437.         filenameNone = (''.join(c for c in unicode(videoID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".none"
  438.         coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  439.         coverFileNone = os.path.join(cacheFolderCoversTMDB, filenameNone)
  440.         if not os.path.exists(coverFile) and not os.path.exists(coverFileNone):
  441.             xbmc.executebuiltin('XBMC.RunScript('+downloadScript+', '+urllib.quote_plus(videoTypeTemp)+', '+urllib.quote_plus(videoID)+', '+urllib.quote_plus(titleTemp)+', '+urllib.quote_plus(yearTemp)+')')
  442.     match = re.compile('src=".+?">.*?<.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  443.     desc = ""
  444.     if match:
  445.         desc = match[0].replace("&amp;", "&")
  446.     match = re.compile('Director:</dt><dd>(.+?)<', re.DOTALL).findall(videoDetails)
  447.     director = ""
  448.     if match:
  449.         director = match[0].strip()
  450.     match = re.compile('<span class="genre.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  451.     genre = ""
  452.     if match:
  453.         genre = match[0]
  454.     match = re.compile('<span class="rating.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  455.     rating = ""
  456.     if rating:
  457.         rating = match[0]
  458.     title = title.replace("&amp;", "&")
  459.     nextMode = "playVideoMain"
  460.     if browseTvShows and videoType == "tvshow":
  461.         nextMode = "listSeasons"
  462.     added = False
  463.     if "/MyList" in url and videoTypeTemp==type:
  464.         addVideoDirR(title, videoID, nextMode, thumbUrl, videoType, desc, duration, year, mpaa, director, genre, rating)
  465.         added = True
  466.     elif videoType == "movie" and hideMovies:
  467.         pass
  468.     elif videoTypeTemp==type or type=="both":
  469.         addVideoDir(title, videoID, nextMode, thumbUrl, videoType, desc, duration, year, mpaa, director, genre, rating)
  470.         added = True
  471.     return added
  472.  
  473. def makeListsGenresRequest(apidata, count):
  474.     authURL = apidata["contextData"]["userInfo"]["data"]["authURL"]
  475.     return '{"paths":[["genreList",{"from":0,"to":%s},["id","menuName"]],["genreList","summary"]],"authURL":"%s"}' % (str(count), authURL)
  476.    
  477. def listMovieGenres(url, type):
  478.     (apidata, data) = getNetflixPage("/browse")
  479.     data2 = getNetflixAjaxData(apidata, makeListsGenresRequest(apidata, 40))
  480.     xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_LABEL)
  481.     for key in data2["value"]["genres"].keys():
  482.         if key == "$size" or key == "size" or key == "83":
  483.             continue
  484.         gid = data2["value"]["genres"][key]["id"]
  485.         gname = data2["value"]["genres"][key]["menuName"]
  486.         addDir(gname, "/browse/genre/" + str(gid), "listFiltered", "", type)
  487.     xbmcplugin.endOfDirectory(pluginhandle)
  488.  
  489. def listTvGenres(url, type):
  490.     (apidata, data) = getNetflixPage("/browse/genre/83")
  491.     xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_LABEL)
  492.     for key in data["genres"].keys():
  493.         if key == "$size" or key == "size" or key == "83":
  494.             continue
  495.         print "Key: " + key
  496.         print "Value: " + str(data["genres"][key])
  497.         gid = data["genres"][key]["summary"]["id"]
  498.         gname = data["genres"][key]["summary"]["menuName"]
  499.         addDir(gname, "/browse/genre/" + str(gid), "listFiltered", "", type)
  500.     xbmcplugin.endOfDirectory(pluginhandle)
  501.  
  502. def getSeriesId(url):
  503.     print "GetSeriesId url: " + url
  504.     gre = re.compile("/title/([0-9]+)", re.DOTALL).findall(url)
  505.     if gre:
  506.         return gre[0]
  507.     return None
  508.  
  509. def makeSeasonListRequest(apidata, seriesId):
  510.     authURL = apidata["contextData"]["userInfo"]["data"]["authURL"]
  511.     return '{"paths":[["videos", %s, "seasonList", {"from": 0, "to": 40}, "summary"], ["videos", %s, "seasonList", "summary"]],"authURL":"%s"}' % (seriesId, seriesId, authURL)
  512.    
  513. def listSeasons(url, name, thumb):
  514.     print "List Seasons"
  515.     seriesId = getSeriesId(url)
  516.     (apidata, data) = getNetflixPage("/browse/title/" + seriesId)
  517.     data2 = getNetflixAjaxData(apidata, makeSeasonListRequest(apidata, seriesId))
  518.     #print "Seasons list: " + str(data2)
  519.     sort = []
  520.     addVideoDirR("Play Next Episode", seriesId.encode("utf-8"), "playVideoMain", thumb, "tvshow", "", "", "", "", "", "", "")
  521.     standardNames = True
  522.     for key in data2["value"]["seasons"].keys():
  523.         if key == "$size" or key == "size":
  524.             continue
  525.         name = data2["value"]["seasons"][key]["summary"]["name"]
  526.         sort.append([key, name])
  527.         if not re.match("Season [0-9]+", name):
  528.             standardNames = False
  529.     if standardNames:
  530.         sort = sorted(sort, key = lambda x: int(x[1].split(" ")[1]))
  531.     else:
  532.         sort = sorted(sort, key = lambda x: x[1])
  533.     for ix in sort:
  534.         key = ix[0]
  535.         val = data2["value"]["seasons"][key]
  536.         seasonId = val["summary"]["id"]
  537.         addSeasonDir(val["summary"]["name"].encode("utf-8"), str(seasonId), 'listEpisodes', thumb, name, str(seriesId))
  538.     xbmcplugin.endOfDirectory(pluginhandle)
  539.  
  540. def makeEpisodeListRequest(apidata, seasonId):
  541.     authURL = apidata["contextData"]["userInfo"]["data"]["authURL"]
  542.     return '{"paths":[["seasons", %s, "episodes", {"from": -1, "to": 40}, ["summary", "title", "synopsis", "runtime"]], ["seasons", %s, "episodes", {"from": -1, "to": 40}, "interestingMoment", "_260x146", "jpg"], ["seasons", %s, "episodes", "summary"]],"authURL":"%s"}' % (seasonId, seasonId, seasonId, authURL)
  543.  
  544.  
  545. def listEpisodes(seriesId, seasonId):
  546.     xbmcplugin.setContent(pluginhandle, "episodes")
  547.     (apidata, data) = getNetflixPage("/browse/title/" + seriesId)
  548.     data2 = getNetflixAjaxData(apidata, makeEpisodeListRequest(apidata, seasonId))
  549.    
  550.     sort = []
  551.     for key in data2["value"]["videos"].keys():
  552.         if key == "$size" or key == "size":
  553.             continue
  554.         sort.append([key, data2["value"]["videos"][key]["summary"]["episode"]])
  555.     sort = sorted(sort, key = lambda x: x[1])
  556.     for ix in sort:
  557.         key = ix[0]
  558.        
  559.         val = data2["value"]["videos"][key]
  560.         title = val["title"].encode("utf-8")
  561.         episode = val["summary"]["episode"]
  562.         season = val["summary"]["season"]
  563.         synopsis = val["synopsis"]
  564.         runtime = val["runtime"]
  565.         eid = val["summary"]["id"]
  566.         thumb = val["interestingMoment"]["_260x146"]["jpg"]["url"]
  567.         print "Thumb: " + thumb
  568.         addEpisodeDir("Episode " + str(episode) + " - " + title, str(eid), "playVideoMain", thumb, synopsis, str(runtime), str(season), str(episode), seriesId, "")
  569.     xbmc.executebuiltin('Container.SetViewMode(504)')
  570.     xbmcplugin.endOfDirectory(pluginhandle)
  571.  
  572.  
  573. def listViewingActivity(type):
  574.     pDialog = xbmcgui.DialogProgress()
  575.     pDialog.create('NetfliXBMC', translation(30142)+"...")
  576.     if not singleProfile:
  577.         setProfile()
  578.     xbmcplugin.setContent(pluginhandle, "movies")
  579.     content = opener.open(urlMain+"/WiViewingActivity").read()
  580.     count = 0
  581.     videoIDs = []
  582.     spl = content.split('<li data-series=')
  583.     for i in range(1, len(spl), 1):
  584.         entry = spl[i]
  585.         pDialog.update((count+1)*100/len(spl), translation(30142)+"...")
  586.         matchId1 = re.compile('"(.*?)"', re.DOTALL).findall(entry)
  587.         matchId2 = re.compile('data-movieid="(.*?)"', re.DOTALL).findall(entry)
  588.         if matchId1[0]:
  589.             videoID = matchId1[0]
  590.         elif matchId2[0]:
  591.             videoID = matchId2[0]
  592.         match = re.compile('class="col date nowrap">(.+?)<', re.DOTALL).findall(entry)
  593.         date = match[0]
  594.         matchTitle1 = re.compile('class="seriestitle">(.+?)</a>', re.DOTALL).findall(entry)
  595.         matchTitle2 = re.compile('class="col title">.+?>(.+?)<', re.DOTALL).findall(entry)
  596.         if matchId1[0]:
  597.             title = matchTitle1[0].replace("&amp;", "&").replace("&quot;", '"').replace("</span>", "")
  598.         elif matchId2[0]:
  599.             title = matchTitle2[0]
  600.         title = date+" - "+title
  601.         if videoID not in videoIDs:
  602.             videoIDs.append(videoID)
  603.             added = listVideo(videoID, title, "", False, False, type)
  604.             if added:
  605.                 count += 1
  606.             if count == 40:
  607.                 break
  608.     if forceView:
  609.         xbmc.executebuiltin('Container.SetViewMode('+viewIdActivity+')')
  610.     xbmcplugin.endOfDirectory(pluginhandle)
  611.  
  612.  
  613. def getVideoInfo(videoID):
  614.     cacheFile = os.path.join(cacheFolder, videoID+".cache")
  615.     if os.path.exists(cacheFile):
  616.         fh = xbmcvfs.File(cacheFile, 'r')
  617.         content = fh.read()
  618.         fh.close()
  619.     else:
  620.         content = opener.open(urlMain+"/JSON/BOB?movieid="+videoID).read()
  621.         fh = xbmcvfs.File(cacheFile, 'w')
  622.         fh.write(content)
  623.         fh.close()
  624.     return content.replace("\\t","").replace("\\n", "").replace("\\", "")
  625.  
  626.  
  627. def getSeriesInfo(seriesID):
  628.     cacheFile = os.path.join(cacheFolder, seriesID+"_episodes.cache")
  629.     if os.path.exists(cacheFile) and (time.time()-os.path.getmtime(cacheFile) < 60*5):
  630.         fh = xbmcvfs.File(cacheFile, 'r')
  631.         content = fh.read()
  632.         fh.close()
  633.     else:
  634.         url = "http://api-global.netflix.com/desktop/odp/episodes?languages="+language+"&forceEpisodes=true&routing=redirect&video="+seriesID+"&country="+country
  635.         content = opener.open(url).read()
  636.         fh = xbmcvfs.File(cacheFile, 'w')
  637.         fh.write(content)
  638.         fh.close()
  639.     return content
  640.  
  641.  
  642. def addMyListToLibrary():
  643.     if not singleProfile:
  644.         setProfile()
  645.     content = opener.open(urlMain+"/MyList?leid=595&link=seeall").read()
  646.     if not 'id="page-LOGIN"' in content:
  647.         if singleProfile and 'id="page-ProfilesGate"' in content:
  648.             forceChooseProfile()
  649.         else:
  650.             if '<div id="queue"' in content:
  651.                 content = content[content.find('<div id="queue"'):]
  652.             content = content.replace("\\t","").replace("\\n", "").replace("\\", "")
  653.             match1 = re.compile('<span id="dbs(.+?)_.+?alt=".+?"', re.DOTALL).findall(content)
  654.             match2 = re.compile('<span class="title.*?"><a id="b(.+?)_', re.DOTALL).findall(content)
  655.             match3 = re.compile('<a href="http://dvd.netflix.com/WiPlayer\?movieid=(.+?)&', re.DOTALL).findall(content)
  656.             match4 = re.compile('<a class="playHover" href=".+?WiPlayer\?movieid=(.+?)&', re.DOTALL).findall(content)
  657.             match5 = re.compile('"boxart":".+?","titleId":(.+?),', re.DOTALL).findall(content)
  658.             if match1:
  659.                 match = match1
  660.             elif match2:
  661.                 match = match2
  662.             elif match3:
  663.                 match = match3
  664.             elif match4:
  665.                 match = match4
  666.             elif match5:
  667.                 match = match5
  668.             for videoID in match:
  669.                 videoDetails = getVideoInfo(videoID)
  670.                 match = re.compile('<span class="title ".*?>(.+?)<\/span>', re.DOTALL).findall(videoDetails)
  671.                 title = match[0].strip()
  672.                 title = title.replace("&amp;", "&")
  673.                 match = re.compile('<span class="year".*?>(.+?)<\/span>', re.DOTALL).findall(videoDetails)
  674.                 year = ""
  675.                 if match:
  676.                     year = match[0]
  677.                 match = re.compile('<span class="duration.*?".*?>(.+?)<\/span>', re.DOTALL).findall(videoDetails)
  678.                 duration = ""
  679.                 if match:
  680.                     duration = match[0].lower()
  681.                 if "minutes" in duration:
  682.                     try:
  683.                         if year:
  684.                             title = title+" ("+year+")"
  685.                         addMovieToLibrary(videoID, title, False)
  686.                     except:
  687.                         pass
  688.                 else:
  689.                     try:
  690.                         addSeriesToLibrary(videoID, title, "", False)
  691.                     except:
  692.                         pass
  693.             if updateDB:
  694.                 xbmc.executebuiltin('UpdateLibrary(video)')
  695.  
  696.  
  697. def playVideo(id):
  698.     playVideoMain(id)
  699.     xbmc.sleep(5000)
  700.     listitem = xbmcgui.ListItem(path=fakeVidPath)
  701.     xbmcplugin.setResolvedUrl(pluginhandle, True, listitem)
  702.     xbmc.PlayList(xbmc.PLAYLIST_VIDEO).clear()
  703.      
  704.  
  705. def playVideoMain(id):
  706.     xbmc.Player().stop()
  707.     if singleProfile:
  708.         url = urlMain+"/WiPlayer?movieid="+id
  709.     else:
  710.         token = ""
  711.         if addon.getSetting("profile"):
  712.             token = addon.getSetting("profile")
  713.         url = "https://www.netflix.com/SwitchProfile?tkn="+token+"&nextpage="+urllib.quote_plus(urlMain+"/WiPlayer?movieid="+id)
  714.     kiosk = "yes"
  715.     if dontUseKiosk:
  716.         kiosk = "no"
  717.     if osOsx:
  718.         xbmc.executebuiltin("RunPlugin(plugin://plugin.program.chrome.launcher/?url="+urllib.quote_plus(url)+"&mode=showSite&kiosk="+kiosk+")")
  719.         try:
  720.             xbmc.sleep(5000)
  721.             subprocess.Popen('cliclick c:500,500', shell=True)
  722.             subprocess.Popen('cliclick kp:arrow-up', shell=True)
  723.             xbmc.sleep(5000)
  724.             subprocess.Popen('cliclick c:500,500', shell=True)
  725.             subprocess.Popen('cliclick kp:arrow-up', shell=True)
  726.             xbmc.sleep(5000)
  727.             subprocess.Popen('cliclick c:500,500', shell=True)
  728.             subprocess.Popen('cliclick kp:arrow-up', shell=True)
  729.         except:
  730.             pass
  731.     elif osLinux:
  732.         xbmc.executebuiltin("RunPlugin(plugin://plugin.program.chrome.launcher/?url="+urllib.quote_plus(url)+"&mode=showSite&kiosk="+kiosk+")")
  733.         try:
  734.             xbmc.sleep(5000)
  735.             subprocess.Popen('xdotool mousemove 9999 9999', shell=True)
  736.             xbmc.sleep(5000)
  737.             subprocess.Popen('xdotool mousemove 9999 9999', shell=True)
  738.             xbmc.sleep(5000)
  739.             subprocess.Popen('xdotool mousemove 9999 9999', shell=True)
  740.         except:
  741.             pass
  742.     elif osWin:
  743.         if winBrowser == 1:
  744.             path = 'C:\\Program Files\\Internet Explorer\\iexplore.exe'
  745.             path64 = 'C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe'
  746.             if os.path.exists(path):
  747.                 subprocess.Popen('"'+path+'" -k "'+url+'"', shell=False)
  748.             elif os.path.exists(path64):
  749.                 subprocess.Popen('"'+path64+'" -k "'+url+'"', shell=False)
  750.         else:
  751.             xbmc.executebuiltin("RunPlugin(plugin://plugin.program.chrome.launcher/?url="+urllib.quote_plus(url)+"&mode=showSite&kiosk="+kiosk+")")
  752.         if useUtility:
  753.             subprocess.Popen('"'+utilityPath+'"', shell=False)
  754.     if remoteControl:
  755.         myWindow = window('window.xml', addon.getAddonInfo('path'), 'default',)
  756.         myWindow.doModal()
  757.        
  758.  
  759. def configureUtility():
  760.     if osWin:
  761.         subprocess.Popen('"'+utilityPath+'"'+' config=yes', shell=False)
  762.  
  763.  
  764. def deleteCookies():
  765.     if os.path.exists(cookieFile):
  766.         os.remove(cookieFile)
  767.         xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,Cookies have been deleted!,5000,'+icon+')')
  768.  
  769.  
  770. def deleteCache():
  771.     if os.path.exists(cacheFolder):
  772.         try:
  773.             shutil.rmtree(cacheFolder)
  774.             xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,Cache has been deleted!,5000,'+icon+')')
  775.         except:
  776.             pass
  777.  
  778.  
  779. def resetAddon():
  780.     dialog = xbmcgui.Dialog()
  781.     if dialog.yesno("NetfliXBMC:", "Really reset the addon?"):
  782.       if os.path.exists(addonUserDataFolder):
  783.           try:
  784.               shutil.rmtree(addonUserDataFolder)
  785.               xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,Addon has been reset!,5000,'+icon+')')
  786.           except:
  787.               pass
  788.  
  789.  
  790. def search(type):
  791.     keyboard = xbmc.Keyboard('', translation(30008))
  792.     keyboard.doModal()
  793.     if keyboard.isConfirmed() and keyboard.getText():
  794.         search_string = keyboard.getText().replace(" ", "+")
  795.         listSearchVideos("http://api-global.netflix.com/desktop/search/instantsearch?esn=www&term="+search_string+"&locale="+language+"&country="+country+"&authURL="+auth+"&_retry=0&routing=redirect", type)
  796.  
  797.  
  798. def addToQueue(id):
  799.     opener.open(urlMain+"/AddToQueue?movieid="+id+"&authURL="+auth)
  800.     xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30144))+',3000,'+icon+')')
  801.  
  802.  
  803. def removeFromQueue(id):
  804.     opener.open(urlMain+"/QueueDelete?movieid="+id+"&authURL="+auth)
  805.     xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30145))+',3000,'+icon+')')
  806.     xbmc.executebuiltin("Container.Refresh")
  807.  
  808.  
  809. def login():
  810.     content = opener.open(urlMain+"/Login").read()
  811.     match = re.compile('"LOCALE":"(.+?)"', re.DOTALL).findall(content)
  812.     if match and not addon.getSetting("language"):
  813.         addon.setSetting("language", match[0])
  814.     if not "Sorry, Netflix is not available in your country yet." in content and not "Sorry, Netflix hasn't come to this part of the world yet" in content:
  815.         match = re.compile('id="signout".+?authURL=(.+?)"', re.DOTALL).findall(content)
  816.         if match:
  817.             addon.setSetting("auth", match[0])
  818.         if 'id="page-LOGIN"' in content:
  819.             match = re.compile('name="authURL" value="(.+?)"', re.DOTALL).findall(content)
  820.             authUrl = match[0]
  821.             addon.setSetting("auth", authUrl)
  822.             content = opener.open("https://signup.netflix.com/Login", "authURL="+urllib.quote_plus(authUrl)+"&email="+urllib.quote_plus(username)+"&password="+urllib.quote_plus(password)+"&RememberMe=on").read()
  823.             match = re.compile('"LOCALE":"(.+?)"', re.DOTALL).findall(content)
  824.             if match and not addon.getSetting("language"):
  825.                 addon.setSetting("language", match[0])
  826.             cj.save(cookieFile)
  827.         if not addon.getSetting("profile") and not singleProfile:
  828.             chooseProfile()
  829.         elif not singleProfile and showProfiles:
  830.             chooseProfile()
  831.         print "Login OK"
  832.         return True
  833.     else:
  834.         xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30126))+',10000,'+icon+')')
  835.         print "Login Failed"
  836.         return False
  837.  
  838.  
  839. def setProfile():
  840.     token = addon.getSetting("profile")
  841.     opener.open("https://www.netflix.com/ProfilesGate?nextpage=http%3A%2F%2Fwww.netflix.com%2FDefault")
  842.     opener.open("https://api-global.netflix.com/desktop/account/profiles/switch?switchProfileGuid="+token)
  843.     cj.save(cookieFile)
  844.  
  845.  
  846. def chooseProfile():
  847.     content = opener.open("https://www.netflix.com/ProfilesGate?nextpage=http%3A%2F%2Fwww.netflix.com%2FDefault").read()
  848.     print "Profile Content: " + content
  849.     match = re.compile('"guid":"(.+?)","profileName":"(.+?)"', re.DOTALL).findall(content)
  850.     profiles = []
  851.     tokens = []
  852.     for t, p in match:
  853.         profiles.append(p)
  854.         tokens.append(t)
  855.     print "Profiles: " + str(profiles)
  856.     for nr in range(len(profiles)):
  857.     if profiles[nr] != "Kids":
  858.         break
  859.     #dialog = xbmcgui.Dialog()
  860.     #nr = dialog.select(translation(30113), profiles)
  861.     print "Selected profile: " + tokens[nr]
  862.     print "In choose profile"
  863.     if nr >= 0:
  864.         token = tokens[nr]
  865.         # Profile selection isn't remembered, so it has to be executed before every requests (setProfile)
  866.         # If you know a solution for this, please let me know
  867.         # opener.open("https://api-global.netflix.com/desktop/account/profiles/switch?switchProfileGuid="+token)
  868.         addon.setSetting("profile", token)
  869.         cj.save(cookieFile)
  870.  
  871.  
  872. def forceChooseProfile():
  873.     #addon.setSetting("singleProfile", "false")
  874.     #xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30111))+',5000,'+icon+')')
  875.     chooseProfile()
  876.  
  877.  
  878. def addMovieToLibrary(movieID, title, singleUpdate=True):
  879.     movieFolderName = (''.join(c for c in unicode(title, 'utf-8') if c not in '/\\:?"*|<>')).strip(' .')
  880.     dir = os.path.join(libraryFolderMovies, movieFolderName)
  881.     if not os.path.isdir(dir):
  882.         xbmcvfs.mkdir(dir)
  883.         fh = xbmcvfs.File(os.path.join(dir, "movie.strm"), 'w')
  884.         fh.write("plugin://plugin.video.netflixbmc/?mode=playVideo&url="+movieID)
  885.         fh.close()
  886.     if updateDB and singleUpdate:
  887.         xbmc.executebuiltin('UpdateLibrary(video)')
  888.  
  889.  
  890. def addSeriesToLibrary(seriesID, seriesTitle, season, singleUpdate=True):
  891.     seriesFolderName = (''.join(c for c in unicode(seriesTitle, 'utf-8') if c not in '/\\:?"*|<>')).strip(' .')
  892.     seriesDir = os.path.join(libraryFolderTV, seriesFolderName)
  893.     if not os.path.isdir(seriesDir):
  894.         xbmcvfs.mkdir(seriesDir)
  895.     content = getSeriesInfo(seriesID)
  896.     content = json.loads(content)
  897.     for test in content["episodes"]:
  898.         for item in test:
  899.             episodeSeason = str(item["season"])
  900.             seasonCheck = True
  901.             if season:
  902.                 seasonCheck = episodeSeason == season
  903.             if seasonCheck:
  904.                 seasonDir = os.path.join(seriesDir, "Season "+episodeSeason)
  905.                 if not os.path.isdir(seasonDir):
  906.                     xbmcvfs.mkdir(seasonDir)
  907.                 episodeID = str(item["episodeId"])
  908.                 episodeNr = str(item["episode"])
  909.                 episodeTitle = item["title"].encode('utf-8')
  910.                 if len(episodeNr) == 1:
  911.                     episodeNr = "0"+episodeNr
  912.                 seasonNr = episodeSeason
  913.                 if len(seasonNr) == 1:
  914.                     seasonNr = "0"+seasonNr
  915.                 filename = "S"+seasonNr+"E"+episodeNr+" - "+episodeTitle+".strm"
  916.                 filename = (''.join(c for c in unicode(filename, 'utf-8') if c not in '/\\:?"*|<>')).strip(' .')
  917.                 fh = xbmcvfs.File(os.path.join(seasonDir, filename), 'w')
  918.                 fh.write("plugin://plugin.video.netflixbmc/?mode=playVideo&url="+episodeID)
  919.                 fh.close()
  920.     if updateDB and singleUpdate:
  921.         xbmc.executebuiltin('UpdateLibrary(video)')
  922.  
  923.  
  924. def playTrailer(title):
  925.     try:
  926.         content = opener.open("http://gdata.youtube.com/feeds/api/videos?vq="+title.strip().replace(" ", "+")+"+trailer&racy=include&orderby=relevance").read()
  927.         match = re.compile('<id>http://gdata.youtube.com/feeds/api/videos/(.+?)</id>', re.DOTALL).findall(content.split('<entry>')[1])
  928.         xbmc.Player().play("plugin://plugin.video.youtube/?path=/root/video&action=play_video&videoid=" + match[0])
  929.     except:
  930.         pass
  931.  
  932.  
  933. def translation(id):
  934.     return addon.getLocalizedString(id).encode('utf-8')
  935.  
  936.  
  937. def parameters_string_to_dict(parameters):
  938.     paramDict = {}
  939.     if parameters:
  940.         paramPairs = parameters[1:].split("&")
  941.         for paramsPair in paramPairs:
  942.             paramSplits = paramsPair.split('=')
  943.             if (len(paramSplits)) == 2:
  944.                 paramDict[paramSplits[0]] = paramSplits[1]
  945.     return paramDict
  946.  
  947.  
  948. def addDir(name, url, mode, iconimage, type=""):
  949.     u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&type="+str(type)+"&thumb="+urllib.quote_plus(iconimage)
  950.     ok = True
  951.     liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  952.     liz.setInfo(type="video", infoLabels={"title": name})
  953.     entries = []
  954.     if "/MyList" in url:
  955.         entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addMyListToLibrary)',))
  956.     if not singleProfile:
  957.         entries.append((translation(30110), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=chooseProfile)',))
  958.     liz.setProperty("fanart_image", defaultFanart)
  959.     liz.addContextMenuItems(entries)
  960.     ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  961.     return ok
  962.  
  963.  
  964. def addVideoDir(name, url, mode, iconimage, videoType="", desc="", duration="", year="", mpaa="", director="", genre="", rating=""):
  965.     filename = (''.join(c for c in unicode(url, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  966.     print "Filename: " + filename
  967.     coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  968.     fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  969.     if os.path.exists(coverFile):
  970.         iconimage = coverFile
  971.     u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&thumb="+urllib.quote_plus(iconimage)
  972.     ok = True
  973.     liz = xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage)
  974.     liz.setInfo(type="video", infoLabels={"title": name, "plot": desc, "duration": duration, "year": year, "mpaa": mpaa, "director": director, "genre": genre, "rating": rating})
  975.     #if os.path.exists(fanartFile):
  976.     #    liz.setProperty("fanart_image", fanartFile)
  977.     #elif os.path.exists(coverFile):
  978.     #    liz.setProperty("fanart_image", coverFile)
  979.     entries = []
  980.     if videoType == "tvshow":
  981.         if browseTvShows:
  982.             entries.append((translation(30121), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=playVideoMain&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  983.         else:
  984.             entries.append((translation(30118), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listSeasons&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  985.     if videoType != "episode":
  986.         entries.append((translation(30134), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=playTrailer&url='+urllib.quote_plus(name)+')',))
  987.         entries.append((translation(30114), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addToQueue&url='+urllib.quote_plus(url)+')',))
  988.         entries.append((translation(30140), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=movie)',))
  989.         entries.append((translation(30141), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=tv)',))
  990.     if videoType == "tvshow":
  991.         entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addSeriesToLibrary&url=&name='+urllib.quote_plus(name.strip())+'&seriesID='+urllib.quote_plus(url)+')',))
  992.     elif videoType == "movie":
  993.         entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addMovieToLibrary&url='+urllib.quote_plus(url)+'&name='+urllib.quote_plus(name.strip()+' ('+year+')')+')',))
  994.     liz.addContextMenuItems(entries)
  995.     ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  996.     return ok
  997.  
  998.  
  999. def addVideoDirR(name, url, mode, iconimage, videoType="", desc="", duration="", year="", mpaa="", director="", genre="", rating=""):
  1000.     filename = (''.join(c for c in unicode(url, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  1001.     coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  1002.     fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  1003.     if os.path.exists(coverFile):
  1004.         iconimage = coverFile
  1005.     u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&thumb="+urllib.quote_plus(iconimage)
  1006.     ok = True
  1007.     liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  1008.     liz.setInfo(type="video", infoLabels={"title": name, "plot": desc, "duration": duration, "year": year, "mpaa": mpaa, "director": director, "genre": genre, "rating": rating})
  1009.     if os.path.exists(fanartFile):
  1010.         liz.setProperty("fanart_image", fanartFile)
  1011.     elif os.path.exists(coverFile):
  1012.         liz.setProperty("fanart_image", coverFile)
  1013.     entries = []
  1014.     if videoType == "tvshow":
  1015.         if browseTvShows:
  1016.             entries.append((translation(30121), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=playVideoMain&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  1017.         else:
  1018.             entries.append((translation(30118), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listSeasons&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  1019.     entries.append((translation(30134), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=playTrailer&url='+urllib.quote_plus(name)+')',))
  1020.     entries.append((translation(30115), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=removeFromQueue&url='+urllib.quote_plus(url)+')',))
  1021.     entries.append((translation(30140), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=movie)',))
  1022.     entries.append((translation(30141), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=tv)',))
  1023.     if videoType == "tvshow":
  1024.         entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addSeriesToLibrary&url=&name='+str(name.strip())+'&seriesID='+str(url)+')',))
  1025.     elif videoType == "movie":
  1026.         entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addMovieToLibrary&url='+urllib.quote_plus(url)+'&name='+str(name.strip()+' ('+year+')')+')',))
  1027.     liz.addContextMenuItems(entries)
  1028.     ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  1029.     return ok
  1030.  
  1031.  
  1032. def addSeasonDir(name, url, mode, iconimage, seriesName, seriesID):
  1033.     filename = (''.join(c for c in unicode(seriesID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  1034.     fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  1035.     coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  1036.     u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&seriesID="+urllib.quote_plus(seriesID)
  1037.     ok = True
  1038.     liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  1039.     liz.setInfo(type="video", infoLabels={"title": name})
  1040.     if os.path.exists(fanartFile):
  1041.         liz.setProperty("fanart_image", fanartFile)
  1042.     elif os.path.exists(coverFile):
  1043.         liz.setProperty("fanart_image", coverFile)
  1044.     entries = []
  1045.     entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addSeriesToLibrary&url='+urllib.quote_plus(url)+'&name='+str(seriesName.strip())+'&seriesID='+str(seriesID)+')',))
  1046.     liz.addContextMenuItems(entries)
  1047.     ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  1048.     return ok
  1049.  
  1050.  
  1051. def addEpisodeDir(name, url, mode, iconimage, desc="", duration="", season="", episodeNr="", seriesID="", playcount=""):
  1052.     filename = (''.join(c for c in unicode(seriesID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  1053.     fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  1054.     coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  1055.     u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)
  1056.     ok = True
  1057.     liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  1058.     liz.setInfo(type="video", infoLabels={"title": name, "plot": desc, "duration": duration, "season": season, "episode": episodeNr, "playcount": playcount})
  1059.     if os.path.exists(fanartFile):
  1060.         liz.setProperty("fanart_image", fanartFile)
  1061.     elif os.path.exists(coverFile):
  1062.         liz.setProperty("fanart_image", coverFile)
  1063.     ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  1064.     return ok
  1065.  
  1066.  
  1067. class window(xbmcgui.WindowXMLDialog):
  1068.     def onAction(self, action):
  1069.         ACTION_SELECT_ITEM = 7
  1070.         ACTION_PARENT_DIR = 9
  1071.         ACTION_PREVIOUS_MENU = 10
  1072.         ACTION_STOP = 13
  1073.         ACTION_SHOW_INFO = 11
  1074.         ACTION_SHOW_GUI = 18
  1075.         ACTION_MOVE_LEFT = 1
  1076.         ACTION_MOVE_RIGHT = 2
  1077.         ACTION_MOVE_UP = 3
  1078.         ACTION_MOVE_DOWN = 4
  1079.         KEY_BUTTON_BACK = 275
  1080.         if osWin:
  1081.             proc = subprocess.Popen('WMIC PROCESS get Caption', shell=True, stdout=subprocess.PIPE)
  1082.             procAll = ""
  1083.             for line in proc.stdout:
  1084.                 procAll+=line
  1085.             if "chrome.exe" in procAll:
  1086.                 if action in [ACTION_SHOW_INFO, ACTION_SHOW_GUI, ACTION_STOP, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU, KEY_BUTTON_BACK]:
  1087.                     subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=Close', shell=False)
  1088.                     self.close()
  1089.                 elif action==ACTION_SELECT_ITEM:
  1090.                     subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=PlayPause', shell=False)
  1091.                 elif action==ACTION_MOVE_LEFT:
  1092.                     subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=SeekLeft', shell=False)
  1093.                 elif action==ACTION_MOVE_RIGHT:
  1094.                     subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=SeekRight', shell=False)
  1095.                 elif action==ACTION_MOVE_UP:
  1096.                     subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=VolumeUp', shell=False)
  1097.                 elif action==ACTION_MOVE_DOWN:
  1098.                     subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=VolumeDown', shell=False)
  1099.             else:
  1100.                 self.close()
  1101.         elif osLinux:
  1102.             proc = subprocess.Popen('/bin/ps ax', shell=True, stdout=subprocess.PIPE)
  1103.             procAll = ""
  1104.             for line in proc.stdout:
  1105.                 procAll+=line
  1106.             if "chrome" in procAll or "chromium" in procAll:
  1107.                 if action in [ACTION_SHOW_INFO, ACTION_SHOW_GUI, ACTION_STOP, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU, KEY_BUTTON_BACK]:
  1108.                     subprocess.Popen('xdotool key alt+F4', shell=True)
  1109.                     self.close()
  1110.                 elif action==ACTION_SELECT_ITEM:
  1111.                     subprocess.Popen('xdotool key Return', shell=True)
  1112.                 elif action==ACTION_MOVE_LEFT:
  1113.                     subprocess.Popen('xdotool key Left', shell=True)
  1114.                 elif action==ACTION_MOVE_RIGHT:
  1115.                     subprocess.Popen('xdotool key Right', shell=True)
  1116.                 elif action==ACTION_MOVE_UP:
  1117.                     subprocess.Popen('xdotool key Up', shell=True)
  1118.                 elif action==ACTION_MOVE_DOWN:
  1119.                     subprocess.Popen('xdotool key Down', shell=True)
  1120.             else:
  1121.                 self.close()
  1122.         elif osOSX:
  1123.             proc = subprocess.Popen('/bin/ps ax', shell=True, stdout=subprocess.PIPE)
  1124.             procAll = ""
  1125.             for line in proc.stdout:
  1126.                 procAll+=line
  1127.             if "chrome" in procAll:
  1128.                 if action in [ACTION_SHOW_INFO, ACTION_SHOW_GUI, ACTION_STOP, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU, KEY_BUTTON_BACK]:
  1129.                     subprocess.Popen('cliclick kd:alt', shell=True)
  1130.                     subprocess.Popen('cliclick kp:f4', shell=True)
  1131.                     self.close()
  1132.                 elif action==ACTION_SELECT_ITEM:
  1133.                     subprocess.Popen('cliclick kp:return', shell=True)
  1134.                 elif action==ACTION_MOVE_LEFT:
  1135.                     subprocess.Popen('cliclick kp:arrow-left', shell=True)
  1136.                 elif action==ACTION_MOVE_RIGHT:
  1137.                     subprocess.Popen('cliclick kp:arrow-right', shell=True)
  1138.                 elif action==ACTION_MOVE_UP:
  1139.                     subprocess.Popen('cliclick kp:arrow-up', shell=True)
  1140.                 elif action==ACTION_MOVE_DOWN:
  1141.                     subprocess.Popen('cliclick kp:arrow-down', shell=True)
  1142.             else:
  1143.                 self.close()
  1144.  
  1145.  
  1146. params = parameters_string_to_dict(sys.argv[2])
  1147. mode = urllib.unquote_plus(params.get('mode', ''))
  1148. url = urllib.unquote_plus(params.get('url', ''))
  1149. thumb = urllib.unquote_plus(params.get('thumb', ''))
  1150. name = urllib.unquote_plus(params.get('name', ''))
  1151. season = urllib.unquote_plus(params.get('season', ''))
  1152. seriesID = urllib.unquote_plus(params.get('seriesID', ''))
  1153. type = urllib.unquote_plus(params.get('type', ''))
  1154.  
  1155. if mode == 'main':
  1156.     main(type)
  1157. elif mode == 'wiHome':
  1158.     wiHome(type)
  1159. elif mode == "myList":
  1160.     myList(url, type)
  1161. elif mode == "newArrivals":
  1162.     newArrivals(url, type)
  1163. elif mode == "listTvGenres":
  1164.     listTvGenres(url, type)
  1165. elif mode == "listMovieGenres":
  1166.     listMovieGenres(url, type)
  1167. elif mode == "listFiltered":
  1168.     listFiltered(url, type)
  1169. elif mode == 'listVideos':
  1170.     listVideos(url, type)
  1171. elif mode == 'listSliderVideos':
  1172.     listSliderVideos(url, type)
  1173. elif mode == 'listSearchVideos':
  1174.     listSearchVideos(url, type)
  1175. elif mode == 'addToQueue':
  1176.     addToQueue(url)
  1177. elif mode == 'removeFromQueue':
  1178.     removeFromQueue(url)
  1179. elif mode == 'playVideo':
  1180.     playVideo(url)
  1181. elif mode == 'playVideoMain':
  1182.     playVideoMain(url)
  1183. elif mode == 'search':
  1184.     search(type)
  1185. elif mode == 'login':
  1186.     login()
  1187. elif mode == 'chooseProfile':
  1188.     chooseProfile()
  1189. elif mode == 'listGenres':
  1190.     listGenres(url, type)
  1191. elif mode == 'listTvGenres':
  1192.     listTvGenres(type)
  1193. elif mode == 'listViewingActivity':
  1194.     listViewingActivity(type)
  1195. elif mode == 'listSeasons':
  1196.     listSeasons(url, name, thumb)
  1197. elif mode == 'listEpisodes':
  1198.     listEpisodes(seriesID, url)
  1199. elif mode == 'configureUtility':
  1200.     configureUtility()
  1201. elif mode == 'deleteCookies':
  1202.     deleteCookies()
  1203. elif mode == 'deleteCache':
  1204.     deleteCache()
  1205. elif mode == 'resetAddon':
  1206.     resetAddon()
  1207. elif mode == 'playTrailer':
  1208.     playTrailer(url)
  1209. elif mode == 'addMyListToLibrary':
  1210.     addMyListToLibrary()
  1211. elif mode == 'addMovieToLibrary':
  1212.     addMovieToLibrary(url, name)
  1213. elif mode == 'addSeriesToLibrary':
  1214.     addSeriesToLibrary(seriesID, name, url)
  1215. else:
  1216.     index()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement