Guest User

NetfliXBMC Latest Episode Mod default.py

a guest
Sep 26th, 2014
3,212
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. dontUseKiosk = addon.getSetting("dontUseKiosk") == "true"
  46. browseTvShows = addon.getSetting("browseTvShows") == "true"
  47. singleProfile = addon.getSetting("singleProfile") == "true"
  48. showProfiles = addon.getSetting("showProfiles") == "true"
  49. forceView = addon.getSetting("forceView") == "true"
  50. useUtility = addon.getSetting("useUtility") == "true"
  51. remoteControl = addon.getSetting("remoteControl") == "true"
  52. updateDB = addon.getSetting("updateDB") == "true"
  53. useTMDb = addon.getSetting("useTMDb") == "true"
  54. username = addon.getSetting("username")
  55. password = addon.getSetting("password")
  56. viewIdVideos = addon.getSetting("viewIdVideos")
  57. viewIdEpisodes = addon.getSetting("viewIdEpisodesNew")
  58. viewIdActivity = addon.getSetting("viewIdActivity")
  59. winBrowser = int(addon.getSetting("winBrowserNew"))
  60. language = addon.getSetting("language")
  61. resume = True
  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; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2114.2 Safari/537.36"
  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. while (username == "" or password == ""):
  88. addon.openSettings()
  89. username = addon.getSetting("username")
  90. password = addon.getSetting("password")
  91.  
  92. if not addon.getSetting("html5MessageShown"):
  93. dialog = xbmcgui.Dialog()
  94. 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...')
  95. addon.setSetting("html5MessageShown", "true")
  96.  
  97.  
  98. def index():
  99. if login():
  100. addDir(translation(30011), "", 'main', "", "movie")
  101. addDir(translation(30012), "", 'main', "", "tv")
  102. addDir(translation(30143), "", 'wiHome', "", "both")
  103. xbmcplugin.endOfDirectory(pluginhandle)
  104.  
  105.  
  106. def main(type):
  107. addDir(translation(30002), urlMain+"/MyList?leid=595&link=seeall", 'listVideos', "", type)
  108. addDir(translation(30010), "", 'listViewingActivity', "", type)
  109. addDir(translation(30003), urlMain+"/WiRecentAdditionsGallery?nRR=releaseDate&nRT=all&pn=1&np=1&actionMethod=json", 'listVideos', "", type)
  110. if type=="tv":
  111. addDir(translation(30005), urlMain+"/WiGenre?agid=83", 'listVideos', "", type)
  112. addDir(translation(30007), "", 'listTvGenres', "", type)
  113. else:
  114. addDir(translation(30007), "WiGenre", 'listGenres', "", type)
  115. addDir(translation(30009), "KidsAltGenre", 'listGenres', "", type)
  116. addDir(translation(30008), "", 'search', "", type)
  117. xbmcplugin.endOfDirectory(pluginhandle)
  118.  
  119.  
  120. def wiHome(type):
  121. if not singleProfile:
  122. setProfile()
  123. content = opener.open(urlMain+"/WiHome").read()
  124. 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)
  125. match2 = re.compile('class="hd clearfix"><h3><a href="(.+?)">(.+?)<', re.DOTALL).findall(content)
  126. for temp, title, sliderID in match1:
  127. if not "hide-completely" in temp:
  128. addDir(title.strip(), sliderID, 'listSliderVideos', "", type)
  129. for url, title in match2:
  130. if "WiAltGenre" in url or "WiSimilarsByViewType" in url or "WiRecentAdditionsGallery" in url:
  131. addDir(title.strip(), url, 'listVideos', "", type)
  132. xbmcplugin.endOfDirectory(pluginhandle)
  133.  
  134.  
  135. def listVideos(url, type):
  136. pDialog = xbmcgui.DialogProgress()
  137. pDialog.create('NetfliXBMC', translation(30142)+"...")
  138. if not singleProfile:
  139. setProfile()
  140. xbmcplugin.setContent(pluginhandle, "movies")
  141. content = opener.open(url).read()
  142. if not 'id="page-LOGIN"' in content:
  143. if singleProfile and 'id="page-ProfilesGate"' in content:
  144. forceChooseProfile()
  145. else:
  146. if '<div id="queue"' in content:
  147. content = content[content.find('<div id="queue"'):]
  148. content = content.replace("\\t","").replace("\\n", "").replace("\\", "")
  149. match1 = re.compile('<span id="dbs(.+?)_.+?alt=".+?"', re.DOTALL).findall(content)
  150. match2 = re.compile('<span class="title.*?"><a id="b(.+?)_', re.DOTALL).findall(content)
  151. match3 = re.compile('<a href="http://dvd.netflix.com/WiPlayer\?movieid=(.+?)&', re.DOTALL).findall(content)
  152. match4 = re.compile('<a class="playHover" href=".+?WiPlayer\?movieid=(.+?)&', re.DOTALL).findall(content)
  153. match5 = re.compile('"boxart":".+?","titleId":(.+?),', re.DOTALL).findall(content)
  154. if match1:
  155. match = match1
  156. elif match2:
  157. match = match2
  158. elif match3:
  159. match = match3
  160. elif match4:
  161. match = match4
  162. elif match5:
  163. match = match5
  164. i = 1
  165. for videoID in match:
  166. pDialog.update(i*100/len(match), translation(30142)+"...")
  167. listVideo(videoID, "", "", False, False, type)
  168. i+=1
  169. match1 = re.compile('&pn=(.+?)&', re.DOTALL).findall(url)
  170. match2 = re.compile('&from=(.+?)&', re.DOTALL).findall(url)
  171. matchApiRoot = re.compile('"API_ROOT":"(.+?)"', re.DOTALL).findall(content)
  172. matchApiBase = re.compile('"API_BASE_URL":"(.+?)"', re.DOTALL).findall(content)
  173. matchIdentifier = re.compile('"BUILD_IDENTIFIER":"(.+?)"', re.DOTALL).findall(content)
  174. if "agid=" in url and matchApiRoot and matchApiBase and matchIdentifier:
  175. genreID = url[url.find("agid=")+5:]
  176. addDir(translation(30001), matchApiRoot[0]+matchApiBase[0]+"/"+matchIdentifier[0]+"/wigenre?genreId="+genreID+"&full=false&from=51&to=100&_retry=0", 'listVideos', "", type)
  177. elif match1:
  178. currentPage = match1[0]
  179. nextPage = str(int(currentPage)+1)
  180. addDir(translation(30001), url.replace("&pn="+currentPage+"&", "&pn="+nextPage+"&"), 'listVideos', "", type)
  181. elif match2:
  182. currentFrom = match2[0]
  183. nextFrom = str(int(currentFrom)+50)
  184. currentTo = str(int(currentFrom)+49)
  185. nextTo = str(int(currentFrom)+99)
  186. addDir(translation(30001), url.replace("&from="+currentFrom+"&", "&from="+nextFrom+"&").replace("&to="+currentTo+"&", "&to="+nextTo+"&"), 'listVideos', "", type)
  187. if forceView:
  188. xbmc.executebuiltin('Container.SetViewMode('+viewIdVideos+')')
  189. xbmcplugin.endOfDirectory(pluginhandle)
  190. else:
  191. deleteCookies()
  192. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30127))+',15000,'+icon+')')
  193.  
  194.  
  195. def listSliderVideos(sliderID, type):
  196. pDialog = xbmcgui.DialogProgress()
  197. pDialog.create('NetfliXBMC', translation(30142)+"...")
  198. if not singleProfile:
  199. setProfile()
  200. xbmcplugin.setContent(pluginhandle, "movies")
  201. content = opener.open(urlMain+"/WiHome").read()
  202. if not 'id="page-LOGIN"' in content:
  203. if singleProfile and 'id="page-ProfilesGate"' in content:
  204. forceChooseProfile()
  205. else:
  206. content = content.replace("\\t","").replace("\\n", "").replace("\\", "")
  207. contentMain = content
  208. content = content[content.find('id="'+sliderID+'"'):]
  209. content = content[:content.find('class="ft"')]
  210. match = re.compile('<span id="dbs(.+?)_', re.DOTALL).findall(content)
  211. i = 1
  212. for videoID in match:
  213. listVideo(videoID, "", "", False, False, type)
  214. i+=1
  215. spl = contentMain.split('"remainderHTML":')
  216. for i in range(1, len(spl), 1):
  217. entry = spl[i]
  218. entry = entry[:entry.find('"rowId":')]
  219. if '"domId":"'+sliderID+'"' in entry:
  220. match = re.compile('<span id="dbs(.+?)_', re.DOTALL).findall(entry)
  221. i = 1
  222. for videoID in match:
  223. pDialog.update(i*100/(len(match)+10), translation(30142)+"...")
  224. listVideo(videoID, "", "", False, False, type)
  225. i+=1
  226. if forceView:
  227. xbmc.executebuiltin('Container.SetViewMode('+viewIdVideos+')')
  228. xbmcplugin.endOfDirectory(pluginhandle)
  229. else:
  230. deleteCookies()
  231. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30127))+',15000,'+icon+')')
  232.  
  233.  
  234. def listSearchVideos(url, type):
  235. pDialog = xbmcgui.DialogProgress()
  236. pDialog.create('NetfliXBMC', translation(30142)+"...")
  237. if not singleProfile:
  238. setProfile()
  239. xbmcplugin.setContent(pluginhandle, "movies")
  240. content = opener.open(url).read()
  241. content = json.loads(content)
  242. i = 1
  243. if "galleryVideos" in content:
  244. for item in content["galleryVideos"]["items"]:
  245. pDialog.update(i*100/len(content["galleryVideos"]["items"]), translation(30142)+"...")
  246. listVideo(str(item["id"]), "", "", False, False, type)
  247. i+=1
  248. if forceView:
  249. xbmc.executebuiltin('Container.SetViewMode('+viewIdVideos+')')
  250. xbmcplugin.endOfDirectory(pluginhandle)
  251. else:
  252. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30146))+',5000,'+icon+')')
  253.  
  254.  
  255. def listVideo(videoID, title, thumbUrl, tvshowIsEpisode, hideMovies, type):
  256. videoDetails = getVideoInfo(videoID)
  257. match = re.compile('<span class="title.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  258. if not title:
  259. title = match[0].strip()
  260. year = ""
  261. match = re.compile('<span class="year.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  262. if match:
  263. year = match[0]
  264. if not thumbUrl:
  265. match = re.compile('src="(.+?)"', re.DOTALL).findall(videoDetails)
  266. thumbUrl = match[0].replace("/webp/","/images/").replace(".webp",".jpg")
  267. match = re.compile('<span class="mpaaRating.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  268. mpaa = ""
  269. if match:
  270. mpaa = match[0]
  271. match = re.compile('<span class="duration.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  272. duration = ""
  273. if match:
  274. duration = match[0].lower()
  275. if duration.split(' ')[-1] in ["minutes", "minutos", "minuter", "minutter", "minuuttia", "minuten"]:
  276. videoType = "movie"
  277. videoTypeTemp = videoType
  278. duration = duration.split(" ")[0]
  279. else:
  280. videoTypeTemp = "tv"
  281. if tvshowIsEpisode:
  282. videoType = "episode"
  283. year = ""
  284. else:
  285. videoType = "tvshow"
  286. duration = ""
  287. if useTMDb:
  288. yearTemp = year
  289. titleTemp = title
  290. if " - " in titleTemp:
  291. titleTemp = titleTemp[titleTemp.find(" - ")+3:]
  292. if ": " in titleTemp:
  293. titleTemp = titleTemp[:titleTemp.find(": ")]
  294. if "-" in yearTemp:
  295. yearTemp = yearTemp.split("-")[0]
  296. filename = (''.join(c for c in unicode(videoID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  297. filenameNone = (''.join(c for c in unicode(videoID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".none"
  298. coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  299. coverFileNone = os.path.join(cacheFolderCoversTMDB, filenameNone)
  300. if not os.path.exists(coverFile) and not os.path.exists(coverFileNone):
  301. xbmc.executebuiltin('XBMC.RunScript('+downloadScript+', '+urllib.quote_plus(videoTypeTemp)+', '+urllib.quote_plus(videoID)+', '+urllib.quote_plus(titleTemp)+', '+urllib.quote_plus(yearTemp)+')')
  302. match = re.compile('src=".+?">.*?<.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  303. desc = ""
  304. if match:
  305. desc = match[0].replace("&amp;", "&")
  306. match = re.compile('Director:</dt><dd>(.+?)<', re.DOTALL).findall(videoDetails)
  307. director = ""
  308. if match:
  309. director = match[0].strip()
  310. match = re.compile('<span class="genre.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  311. genre = ""
  312. if match:
  313. genre = match[0]
  314. match = re.compile('<span class="rating.*?>(.+?)<', re.DOTALL).findall(videoDetails)
  315. rating = ""
  316. if rating:
  317. rating = match[0]
  318. title = title.replace("&amp;", "&")
  319. nextMode = "playVideoMain"
  320. if browseTvShows and videoType == "tvshow":
  321. nextMode = "listSeasons"
  322. added = False
  323. if "/MyList" in url and videoTypeTemp==type:
  324. addVideoDirR(title, videoID, nextMode, thumbUrl, videoType, desc, duration, year, mpaa, director, genre, rating)
  325. added = True
  326. elif videoType == "movie" and hideMovies:
  327. pass
  328. elif videoTypeTemp==type or type=="both":
  329. addVideoDir(title, videoID, nextMode, thumbUrl, videoType, desc, duration, year, mpaa, director, genre, rating)
  330. added = True
  331. return added
  332.  
  333.  
  334. def listGenres(type, videoType):
  335. if not singleProfile:
  336. setProfile()
  337. xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_LABEL)
  338. content = opener.open(urlMain+"/WiHome").read()
  339. match = re.compile('/'+type+'\\?agid=(.+?)">(.+?)<', re.DOTALL).findall(content)
  340. for genreID, title in match:
  341. if not genreID=="83":
  342. if type=="KidsAltGenre":
  343. addDir(title, urlMain+"/"+type+"?agid="+genreID+"&pn=1&np=1&actionMethod=json", 'listVideos', "", videoType)
  344. else:
  345. addDir(title, urlMain+"/"+type+"?agid="+genreID, 'listVideos', "", videoType)
  346. xbmcplugin.endOfDirectory(pluginhandle)
  347.  
  348.  
  349. def listTvGenres(videoType):
  350. if not singleProfile:
  351. setProfile()
  352. xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_LABEL)
  353. content = opener.open(urlMain+"/WiGenre?agid=83").read()
  354. content = content[content.find('id="subGenres_menu"'):]
  355. content = content[:content.find('</div>')]
  356. match = re.compile('<li ><a href=".+?/WiGenre\\?agid=(.+?)&.+?"><span>(.+?)<', re.DOTALL).findall(content)
  357. for genreID, title in match:
  358. addDir(title, urlMain+"/WiGenre?agid="+genreID, 'listVideos', "", videoType)
  359. xbmcplugin.endOfDirectory(pluginhandle)
  360.  
  361.  
  362. def listSeasons(seriesName, seriesID, thumb):
  363. content = getSeriesInfo(seriesID)
  364. content = json.loads(content)
  365. seasons = []
  366. for item in content["episodes"]:
  367. if item[0]["season"] not in seasons:
  368. seasons.append(item[0]["season"])
  369. for season in seasons:
  370. addSeasonDir("Season "+str(season), str(season), 'listEpisodes', thumb, seriesName, seriesID)
  371. xbmcplugin.endOfDirectory(pluginhandle)
  372.  
  373.  
  374. def listEpisodes(seriesID, season):
  375. xbmcplugin.setContent(pluginhandle, "episodes")
  376. content = getSeriesInfo(seriesID)
  377. content = json.loads(content)
  378. for test in content["episodes"]:
  379. for item in test:
  380. episodeSeason = str(item["season"])
  381. if episodeSeason == season:
  382. episodeID = str(item["episodeId"])
  383. episodeNr = str(item["episode"])
  384. episodeTitle = item["title"].encode('utf-8')
  385. duration = item["runtime"]
  386. bookmarkPosition = item["bookmarkPosition"]
  387. playcount=0
  388. if (float(bookmarkPosition)/float(duration))>=0.9:
  389. playcount=1
  390. desc = item["synopsis"].encode('utf-8')
  391. try:
  392. thumb = item["stills"][0]["url"]
  393. except:
  394. thumb = ""
  395. addEpisodeDir(episodeTitle, episodeID, 'playVideoMain', thumb, desc, str(duration), season, episodeNr, seriesID, playcount)
  396. if forceView:
  397. xbmc.executebuiltin('Container.SetViewMode('+viewIdEpisodes+')')
  398. xbmcplugin.endOfDirectory(pluginhandle)
  399.  
  400.  
  401. #if user selects first episode, return first unplayed episode
  402. #otherwise return episode
  403. def resume(seriesID, episodeID):
  404. content = getSeriesInfoNoCache(seriesID)
  405. content = json.loads(content)
  406. firstEpisode = str(content["episodes"][0][0]["episodeId"])
  407. if episodeID == firstEpisode:
  408. for test in content["episodes"]:
  409. for item in test:
  410. currentEpisodeID = str(item["episodeId"])
  411. duration = item["runtime"]
  412. bookmarkPosition = item["bookmarkPosition"]
  413. if (float(bookmarkPosition)/float(duration))<0.9:
  414. return currentEpisodeID
  415. return firstEpisode
  416. return episodeID
  417.  
  418.  
  419. def listViewingActivity(type):
  420. pDialog = xbmcgui.DialogProgress()
  421. pDialog.create('NetfliXBMC', translation(30142)+"...")
  422. if not singleProfile:
  423. setProfile()
  424. xbmcplugin.setContent(pluginhandle, "movies")
  425. content = opener.open(urlMain+"/WiViewingActivity").read()
  426. count = 0
  427. videoIDs = []
  428. spl = content.split('<li data-series=')
  429. for i in range(1, len(spl), 1):
  430. entry = spl[i]
  431. pDialog.update((count+1)*100/len(spl), translation(30142)+"...")
  432. matchId1 = re.compile('"(.*?)"', re.DOTALL).findall(entry)
  433. matchId2 = re.compile('data-movieid="(.*?)"', re.DOTALL).findall(entry)
  434. if matchId1[0]:
  435. videoID = matchId1[0]
  436. elif matchId2[0]:
  437. videoID = matchId2[0]
  438. match = re.compile('class="col date nowrap">(.+?)<', re.DOTALL).findall(entry)
  439. date = match[0]
  440. matchTitle1 = re.compile('class="seriestitle">(.+?)</a>', re.DOTALL).findall(entry)
  441. matchTitle2 = re.compile('class="col title">.+?>(.+?)<', re.DOTALL).findall(entry)
  442. if matchId1[0]:
  443. title = matchTitle1[0].replace("&amp;", "&").replace("&quot;", '"').replace("</span>", "")
  444. elif matchId2[0]:
  445. title = matchTitle2[0]
  446. title = date+" - "+title
  447. if videoID not in videoIDs:
  448. videoIDs.append(videoID)
  449. added = listVideo(videoID, title, "", False, False, type)
  450. if added:
  451. count += 1
  452. if count == 40:
  453. break
  454. if forceView:
  455. xbmc.executebuiltin('Container.SetViewMode('+viewIdActivity+')')
  456. xbmcplugin.endOfDirectory(pluginhandle)
  457.  
  458.  
  459. def getVideoInfo(videoID):
  460. cacheFile = os.path.join(cacheFolder, videoID+".cache")
  461. if os.path.exists(cacheFile):
  462. fh = xbmcvfs.File(cacheFile, 'r')
  463. content = fh.read()
  464. fh.close()
  465. else:
  466. content = opener.open(urlMain+"/JSON/BOB?movieid="+videoID).read()
  467. fh = xbmcvfs.File(cacheFile, 'w')
  468. fh.write(content)
  469. fh.close()
  470. return content.replace("\\t","").replace("\\n", "").replace("\\", "")
  471.  
  472.  
  473. def getSeriesInfoNoCache(seriesID):
  474. cacheFile = os.path.join(cacheFolder, seriesID+"_episodes.cache")
  475. url = "http://api-global.netflix.com/desktop/odp/episodes?languages="+language+"&forceEpisodes=true&routing=redirect&video="+seriesID+"&country="+country
  476. content = opener.open(url).read()
  477. fh = xbmcvfs.File(cacheFile, 'w')
  478. fh.write(content)
  479. fh.close()
  480. return content
  481.  
  482.  
  483. def getSeriesInfo(seriesID):
  484. cacheFile = os.path.join(cacheFolder, seriesID+"_episodes.cache")
  485. if os.path.exists(cacheFile) and (time.time()-os.path.getmtime(cacheFile) < 60*5):
  486. fh = xbmcvfs.File(cacheFile, 'r')
  487. content = fh.read()
  488. fh.close()
  489. else:
  490. url = "http://api-global.netflix.com/desktop/odp/episodes?languages="+language+"&forceEpisodes=true&routing=redirect&video="+seriesID+"&country="+country
  491. content = opener.open(url).read()
  492. fh = xbmcvfs.File(cacheFile, 'w')
  493. fh.write(content)
  494. fh.close()
  495. return content
  496.  
  497.  
  498. def addMyListToLibrary():
  499. if not singleProfile:
  500. setProfile()
  501. content = opener.open(urlMain+"/MyList?leid=595&link=seeall").read()
  502. if not 'id="page-LOGIN"' in content:
  503. if singleProfile and 'id="page-ProfilesGate"' in content:
  504. forceChooseProfile()
  505. else:
  506. if '<div id="queue"' in content:
  507. content = content[content.find('<div id="queue"'):]
  508. content = content.replace("\\t","").replace("\\n", "").replace("\\", "")
  509. match1 = re.compile('<span id="dbs(.+?)_.+?alt=".+?"', re.DOTALL).findall(content)
  510. match2 = re.compile('<span class="title.*?"><a id="b(.+?)_', re.DOTALL).findall(content)
  511. match3 = re.compile('<a href="http://dvd.netflix.com/WiPlayer\?movieid=(.+?)&', re.DOTALL).findall(content)
  512. match4 = re.compile('<a class="playHover" href=".+?WiPlayer\?movieid=(.+?)&', re.DOTALL).findall(content)
  513. match5 = re.compile('"boxart":".+?","titleId":(.+?),', re.DOTALL).findall(content)
  514. if match1:
  515. match = match1
  516. elif match2:
  517. match = match2
  518. elif match3:
  519. match = match3
  520. elif match4:
  521. match = match4
  522. elif match5:
  523. match = match5
  524. for videoID in match:
  525. videoDetails = getVideoInfo(videoID)
  526. match = re.compile('<span class="title ".*?>(.+?)<\/span>', re.DOTALL).findall(videoDetails)
  527. title = match[0].strip()
  528. title = title.replace("&amp;", "&")
  529. match = re.compile('<span class="year".*?>(.+?)<\/span>', re.DOTALL).findall(videoDetails)
  530. year = ""
  531. if match:
  532. year = match[0]
  533. match = re.compile('<span class="duration.*?".*?>(.+?)<\/span>', re.DOTALL).findall(videoDetails)
  534. duration = ""
  535. if match:
  536. duration = match[0].lower()
  537. if "minutes" in duration:
  538. try:
  539. if year:
  540. title = title+" ("+year+")"
  541. addMovieToLibrary(videoID, title, False)
  542. except:
  543. pass
  544. else:
  545. try:
  546. addSeriesToLibrary(videoID, title, "", False)
  547. except:
  548. pass
  549. if updateDB:
  550. xbmc.executebuiltin('UpdateLibrary(video)')
  551.  
  552.  
  553. def playVideo(id, seriesID=None):
  554. if seriesID and resume:
  555. id = resume(seriesID, id)
  556. playVideoMain(id)
  557. xbmc.sleep(5000)
  558. listitem = xbmcgui.ListItem(path=fakeVidPath)
  559. xbmcplugin.setResolvedUrl(pluginhandle, True, listitem)
  560. xbmc.PlayList(xbmc.PLAYLIST_VIDEO).clear()
  561.  
  562.  
  563. def playVideoMain(id):
  564. xbmc.Player().stop()
  565. if singleProfile:
  566. url = urlMain+"/WiPlayer?movieid="+id
  567. else:
  568. token = ""
  569. if addon.getSetting("profile"):
  570. token = addon.getSetting("profile")
  571. url = "https://www.netflix.com/SwitchProfile?tkn="+token+"&nextpage="+urllib.quote_plus(urlMain+"/WiPlayer?movieid="+id)
  572. kiosk = "yes"
  573. if dontUseKiosk:
  574. kiosk = "no"
  575. if osOsx:
  576. xbmc.executebuiltin("RunPlugin(plugin://plugin.program.chrome.launcher/?url="+urllib.quote_plus(url)+"&mode=showSite&kiosk="+kiosk+")")
  577. try:
  578. xbmc.sleep(5000)
  579. subprocess.Popen('cliclick c:500,500', shell=True)
  580. subprocess.Popen('cliclick kp:arrow-up', shell=True)
  581. xbmc.sleep(5000)
  582. subprocess.Popen('cliclick c:500,500', shell=True)
  583. subprocess.Popen('cliclick kp:arrow-up', shell=True)
  584. xbmc.sleep(5000)
  585. subprocess.Popen('cliclick c:500,500', shell=True)
  586. subprocess.Popen('cliclick kp:arrow-up', shell=True)
  587. except:
  588. pass
  589. elif osLinux:
  590. xbmc.executebuiltin("RunPlugin(plugin://plugin.program.chrome.launcher/?url="+urllib.quote_plus(url)+"&mode=showSite&kiosk="+kiosk+"&userAgent="+urllib.quote_plus(userAgent)+")")
  591. try:
  592. xbmc.sleep(5000)
  593. subprocess.Popen('xdotool mousemove 9999 9999', shell=True)
  594. xbmc.sleep(5000)
  595. subprocess.Popen('xdotool mousemove 9999 9999', shell=True)
  596. xbmc.sleep(5000)
  597. subprocess.Popen('xdotool mousemove 9999 9999', shell=True)
  598. except:
  599. pass
  600. elif osWin:
  601. if winBrowser == 1:
  602. path = 'C:\\Program Files\\Internet Explorer\\iexplore.exe'
  603. path64 = 'C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe'
  604. if os.path.exists(path):
  605. subprocess.Popen('"'+path+'" -k "'+url+'"', shell=False)
  606. elif os.path.exists(path64):
  607. subprocess.Popen('"'+path64+'" -k "'+url+'"', shell=False)
  608. else:
  609. xbmc.executebuiltin("RunPlugin(plugin://plugin.program.chrome.launcher/?url="+urllib.quote_plus(url)+"&mode=showSite&kiosk="+kiosk+")")
  610. if useUtility:
  611. subprocess.Popen('"'+utilityPath+'"', shell=False)
  612. if remoteControl:
  613. myWindow = window('window.xml', addon.getAddonInfo('path'), 'default',)
  614. myWindow.doModal()
  615.  
  616.  
  617. def configureUtility():
  618. if osWin:
  619. subprocess.Popen('"'+utilityPath+'"'+' config=yes', shell=False)
  620.  
  621.  
  622. def deleteCookies():
  623. if os.path.exists(cookieFile):
  624. os.remove(cookieFile)
  625. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,Cookies have been deleted!,5000,'+icon+')')
  626.  
  627.  
  628. def deleteCache():
  629. if os.path.exists(cacheFolder):
  630. try:
  631. shutil.rmtree(cacheFolder)
  632. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,Cache has been deleted!,5000,'+icon+')')
  633. except:
  634. pass
  635.  
  636.  
  637. def resetAddon():
  638. dialog = xbmcgui.Dialog()
  639. if dialog.yesno("NetfliXBMC:", "Really reset the addon?"):
  640. if os.path.exists(addonUserDataFolder):
  641. try:
  642. shutil.rmtree(addonUserDataFolder)
  643. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,Addon has been reset!,5000,'+icon+')')
  644. except:
  645. pass
  646.  
  647.  
  648. def search(type):
  649. keyboard = xbmc.Keyboard('', translation(30008))
  650. keyboard.doModal()
  651. if keyboard.isConfirmed() and keyboard.getText():
  652. search_string = keyboard.getText().replace(" ", "+")
  653. 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)
  654.  
  655.  
  656. def addToQueue(id):
  657. opener.open(urlMain+"/AddToQueue?movieid="+id+"&authURL="+auth)
  658. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30144))+',3000,'+icon+')')
  659.  
  660.  
  661. def removeFromQueue(id):
  662. opener.open(urlMain+"/QueueDelete?movieid="+id+"&authURL="+auth)
  663. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30145))+',3000,'+icon+')')
  664. xbmc.executebuiltin("Container.Refresh")
  665.  
  666.  
  667. def login():
  668. content = opener.open(urlMain+"/Login").read()
  669. match = re.compile('"LOCALE":"(.+?)"', re.DOTALL).findall(content)
  670. if match and not addon.getSetting("language"):
  671. addon.setSetting("language", match[0])
  672. 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:
  673. match = re.compile('id="signout".+?authURL=(.+?)"', re.DOTALL).findall(content)
  674. if match:
  675. addon.setSetting("auth", match[0])
  676. if 'id="page-LOGIN"' in content:
  677. match = re.compile('name="authURL" value="(.+?)"', re.DOTALL).findall(content)
  678. authUrl = match[0]
  679. addon.setSetting("auth", authUrl)
  680. 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()
  681. match = re.compile('"LOCALE":"(.+?)"', re.DOTALL).findall(content)
  682. if match and not addon.getSetting("language"):
  683. addon.setSetting("language", match[0])
  684. cj.save(cookieFile)
  685. if not addon.getSetting("profile") and not singleProfile:
  686. chooseProfile()
  687. elif not singleProfile and showProfiles:
  688. chooseProfile()
  689. return True
  690. else:
  691. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30126))+',10000,'+icon+')')
  692. return False
  693.  
  694.  
  695. def setProfile():
  696. token = addon.getSetting("profile")
  697. opener.open("https://www.netflix.com/ProfilesGate?nextpage=http%3A%2F%2Fwww.netflix.com%2FDefault")
  698. opener.open("https://api-global.netflix.com/desktop/account/profiles/switch?switchProfileGuid="+token)
  699. cj.save(cookieFile)
  700.  
  701.  
  702. def chooseProfile():
  703. content = opener.open("https://www.netflix.com/ProfilesGate?nextpage=http%3A%2F%2Fwww.netflix.com%2FDefault").read()
  704. match = re.compile('"profileName":"(.+?)".+?token":"(.+?)"', re.DOTALL).findall(content)
  705. profiles = []
  706. tokens = []
  707. for p, t in match:
  708. profiles.append(p)
  709. tokens.append(t)
  710. dialog = xbmcgui.Dialog()
  711. nr = dialog.select(translation(30113), profiles)
  712. if nr >= 0:
  713. token = tokens[nr]
  714. # Profile selection isn't remembered, so it has to be executed before every requests (setProfile)
  715. # If you know a solution for this, please let me know
  716. # opener.open("https://api-global.netflix.com/desktop/account/profiles/switch?switchProfileGuid="+token)
  717. addon.setSetting("profile", token)
  718. cj.save(cookieFile)
  719.  
  720.  
  721. def forceChooseProfile():
  722. addon.setSetting("singleProfile", "false")
  723. xbmc.executebuiltin('XBMC.Notification(NetfliXBMC:,'+str(translation(30111))+',5000,'+icon+')')
  724. chooseProfile()
  725.  
  726.  
  727. def addMovieToLibrary(movieID, title, singleUpdate=True):
  728. movieFolderName = (''.join(c for c in unicode(title, 'utf-8') if c not in '/\\:?"*|<>')).strip(' .')
  729. dir = os.path.join(libraryFolderMovies, movieFolderName)
  730. if not os.path.isdir(dir):
  731. xbmcvfs.mkdir(dir)
  732. fh = xbmcvfs.File(os.path.join(dir, "movie.strm"), 'w')
  733. fh.write("plugin://plugin.video.netflixbmc/?mode=playVideo&url="+movieID)
  734. fh.close()
  735. if updateDB and singleUpdate:
  736. xbmc.executebuiltin('UpdateLibrary(video)')
  737.  
  738.  
  739. def addSeriesToLibrary(seriesID, seriesTitle, season, singleUpdate=True):
  740. seriesFolderName = (''.join(c for c in unicode(seriesTitle, 'utf-8') if c not in '/\\:?"*|<>')).strip(' .')
  741. seriesDir = os.path.join(libraryFolderTV, seriesFolderName)
  742. if not os.path.isdir(seriesDir):
  743. xbmcvfs.mkdir(seriesDir)
  744. content = getSeriesInfo(seriesID)
  745. content = json.loads(content)
  746. for test in content["episodes"]:
  747. for item in test:
  748. episodeSeason = str(item["season"])
  749. seasonCheck = True
  750. if season:
  751. seasonCheck = episodeSeason == season
  752. if seasonCheck:
  753. seasonDir = os.path.join(seriesDir, "Season "+episodeSeason)
  754. if not os.path.isdir(seasonDir):
  755. xbmcvfs.mkdir(seasonDir)
  756. episodeID = str(item["episodeId"])
  757. episodeNr = str(item["episode"])
  758. episodeTitle = item["title"].encode('utf-8')
  759. if len(episodeNr) == 1:
  760. episodeNr = "0"+episodeNr
  761. seasonNr = episodeSeason
  762. if len(seasonNr) == 1:
  763. seasonNr = "0"+seasonNr
  764. filename = "S"+seasonNr+"E"+episodeNr+" - "+episodeTitle+".strm"
  765. filename = (''.join(c for c in unicode(filename, 'utf-8') if c not in '/\\:?"*|<>')).strip(' .')
  766. fh = xbmcvfs.File(os.path.join(seasonDir, filename), 'w')
  767. fh.write("plugin://plugin.video.netflixbmc/?mode=playVideo&url="+episodeID+"&seriesID="+seriesID)
  768. fh.close()
  769. if updateDB and singleUpdate:
  770. xbmc.executebuiltin('UpdateLibrary(video)')
  771.  
  772.  
  773. def playTrailer(title):
  774. try:
  775. content = opener.open("http://gdata.youtube.com/feeds/api/videos?vq="+title.strip().replace(" ", "+")+"+trailer&racy=include&orderby=relevance").read()
  776. match = re.compile('<id>http://gdata.youtube.com/feeds/api/videos/(.+?)</id>', re.DOTALL).findall(content.split('<entry>')[1])
  777. xbmc.Player().play("plugin://plugin.video.youtube/?path=/root/video&action=play_video&videoid=" + match[0])
  778. except:
  779. pass
  780.  
  781.  
  782. def translation(id):
  783. return addon.getLocalizedString(id).encode('utf-8')
  784.  
  785.  
  786. def parameters_string_to_dict(parameters):
  787. paramDict = {}
  788. if parameters:
  789. paramPairs = parameters[1:].split("&")
  790. for paramsPair in paramPairs:
  791. paramSplits = paramsPair.split('=')
  792. if (len(paramSplits)) == 2:
  793. paramDict[paramSplits[0]] = paramSplits[1]
  794. return paramDict
  795.  
  796.  
  797. def addDir(name, url, mode, iconimage, type=""):
  798. u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&type="+str(type)+"&thumb="+urllib.quote_plus(iconimage)
  799. ok = True
  800. liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  801. liz.setInfo(type="video", infoLabels={"title": name})
  802. entries = []
  803. if "/MyList" in url:
  804. entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addMyListToLibrary)',))
  805. if not singleProfile:
  806. entries.append((translation(30110), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=chooseProfile)',))
  807. liz.setProperty("fanart_image", defaultFanart)
  808. liz.addContextMenuItems(entries)
  809. ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  810. return ok
  811.  
  812.  
  813. def addVideoDir(name, url, mode, iconimage, videoType="", desc="", duration="", year="", mpaa="", director="", genre="", rating=""):
  814. filename = (''.join(c for c in unicode(url, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  815. coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  816. fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  817. if os.path.exists(coverFile):
  818. iconimage = coverFile
  819. u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&thumb="+urllib.quote_plus(iconimage)
  820. ok = True
  821. liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  822. liz.setInfo(type="video", infoLabels={"title": name, "plot": desc, "duration": duration, "year": year, "mpaa": mpaa, "director": director, "genre": genre, "rating": rating})
  823. if os.path.exists(fanartFile):
  824. liz.setProperty("fanart_image", fanartFile)
  825. elif os.path.exists(coverFile):
  826. liz.setProperty("fanart_image", coverFile)
  827. entries = []
  828. if videoType == "tvshow":
  829. if browseTvShows:
  830. entries.append((translation(30121), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=playVideoMain&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  831. else:
  832. entries.append((translation(30118), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listSeasons&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  833. if videoType != "episode":
  834. entries.append((translation(30134), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=playTrailer&url='+urllib.quote_plus(name)+')',))
  835. entries.append((translation(30114), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addToQueue&url='+urllib.quote_plus(url)+')',))
  836. entries.append((translation(30140), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=movie)',))
  837. entries.append((translation(30141), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=tv)',))
  838. if videoType == "tvshow":
  839. entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addSeriesToLibrary&url=&name='+urllib.quote_plus(name.strip())+'&seriesID='+urllib.quote_plus(url)+')',))
  840. elif videoType == "movie":
  841. entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addMovieToLibrary&url='+urllib.quote_plus(url)+'&name='+urllib.quote_plus(name.strip()+' ('+year+')')+')',))
  842. liz.addContextMenuItems(entries)
  843. ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  844. return ok
  845.  
  846.  
  847. def addVideoDirR(name, url, mode, iconimage, videoType="", desc="", duration="", year="", mpaa="", director="", genre="", rating=""):
  848. filename = (''.join(c for c in unicode(url, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  849. coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  850. fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  851. if os.path.exists(coverFile):
  852. iconimage = coverFile
  853. u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&thumb="+urllib.quote_plus(iconimage)
  854. ok = True
  855. liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  856. liz.setInfo(type="video", infoLabels={"title": name, "plot": desc, "duration": duration, "year": year, "mpaa": mpaa, "director": director, "genre": genre, "rating": rating})
  857. if os.path.exists(fanartFile):
  858. liz.setProperty("fanart_image", fanartFile)
  859. elif os.path.exists(coverFile):
  860. liz.setProperty("fanart_image", coverFile)
  861. entries = []
  862. if videoType == "tvshow":
  863. if browseTvShows:
  864. entries.append((translation(30121), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=playVideoMain&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  865. else:
  866. entries.append((translation(30118), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listSeasons&url='+urllib.quote_plus(url)+'&thumb='+urllib.quote_plus(iconimage)+')',))
  867. entries.append((translation(30134), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=playTrailer&url='+urllib.quote_plus(name)+')',))
  868. entries.append((translation(30115), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=removeFromQueue&url='+urllib.quote_plus(url)+')',))
  869. entries.append((translation(30140), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=movie)',))
  870. entries.append((translation(30141), 'Container.Update(plugin://plugin.video.netflixbmc/?mode=listVideos&url='+urllib.quote_plus(urlMain+"/WiMovie/"+url)+'&type=tv)',))
  871. if videoType == "tvshow":
  872. entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addSeriesToLibrary&url=&name='+str(name.strip())+'&seriesID='+str(url)+')',))
  873. elif videoType == "movie":
  874. entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addMovieToLibrary&url='+urllib.quote_plus(url)+'&name='+str(name.strip()+' ('+year+')')+')',))
  875. liz.addContextMenuItems(entries)
  876. ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  877. return ok
  878.  
  879.  
  880. def addSeasonDir(name, url, mode, iconimage, seriesName, seriesID):
  881. filename = (''.join(c for c in unicode(seriesID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  882. fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  883. coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  884. u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&seriesID="+urllib.quote_plus(seriesID)
  885. ok = True
  886. liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  887. liz.setInfo(type="video", infoLabels={"title": name})
  888. if os.path.exists(fanartFile):
  889. liz.setProperty("fanart_image", fanartFile)
  890. elif os.path.exists(coverFile):
  891. liz.setProperty("fanart_image", coverFile)
  892. entries = []
  893. entries.append((translation(30122), 'RunPlugin(plugin://plugin.video.netflixbmc/?mode=addSeriesToLibrary&url='+urllib.quote_plus(url)+'&name='+str(seriesName.strip())+'&seriesID='+str(seriesID)+')',))
  894. liz.addContextMenuItems(entries)
  895. ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  896. return ok
  897.  
  898.  
  899. def addEpisodeDir(name, url, mode, iconimage, desc="", duration="", season="", episodeNr="", seriesID="", playcount=""):
  900. filename = (''.join(c for c in unicode(seriesID, 'utf-8') if c not in '/\\:?"*|<>')).strip()+".jpg"
  901. fanartFile = os.path.join(cacheFolderFanartTMDB, filename)
  902. coverFile = os.path.join(cacheFolderCoversTMDB, filename)
  903. u = sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)
  904. ok = True
  905. liz = xbmcgui.ListItem(name, iconImage="DefaultTVShows.png", thumbnailImage=iconimage)
  906. liz.setInfo(type="video", infoLabels={"title": name, "plot": desc, "duration": duration, "season": season, "episode": episodeNr, "playcount": playcount})
  907. if os.path.exists(fanartFile):
  908. liz.setProperty("fanart_image", fanartFile)
  909. elif os.path.exists(coverFile):
  910. liz.setProperty("fanart_image", coverFile)
  911. ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=u, listitem=liz, isFolder=True)
  912. return ok
  913.  
  914.  
  915. class window(xbmcgui.WindowXMLDialog):
  916. def onAction(self, action):
  917. ACTION_SELECT_ITEM = 7
  918. ACTION_PARENT_DIR = 9
  919. ACTION_PREVIOUS_MENU = 10
  920. ACTION_STOP = 13
  921. ACTION_SHOW_INFO = 11
  922. ACTION_SHOW_GUI = 18
  923. ACTION_MOVE_LEFT = 1
  924. ACTION_MOVE_RIGHT = 2
  925. ACTION_MOVE_UP = 3
  926. ACTION_MOVE_DOWN = 4
  927. KEY_BUTTON_BACK = 275
  928. if osWin:
  929. proc = subprocess.Popen('WMIC PROCESS get Caption', shell=True, stdout=subprocess.PIPE)
  930. procAll = ""
  931. for line in proc.stdout:
  932. procAll+=line
  933. if "chrome.exe" in procAll:
  934. if action in [ACTION_SHOW_INFO, ACTION_SHOW_GUI, ACTION_STOP, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU, KEY_BUTTON_BACK]:
  935. subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=Close', shell=False)
  936. self.close()
  937. elif action==ACTION_SELECT_ITEM:
  938. subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=PlayPause', shell=False)
  939. elif action==ACTION_MOVE_LEFT:
  940. subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=SeekLeft', shell=False)
  941. elif action==ACTION_MOVE_RIGHT:
  942. subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=SeekRight', shell=False)
  943. elif action==ACTION_MOVE_UP:
  944. subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=VolumeUp', shell=False)
  945. elif action==ACTION_MOVE_DOWN:
  946. subprocess.Popen('"'+sendKeysPath+'"'+' sendKey=VolumeDown', shell=False)
  947. else:
  948. self.close()
  949. elif osLinux:
  950. proc = subprocess.Popen('/bin/ps ax', shell=True, stdout=subprocess.PIPE)
  951. procAll = ""
  952. for line in proc.stdout:
  953. procAll+=line
  954. if "chrome" in procAll or "chromium" in procAll:
  955. if action in [ACTION_SHOW_INFO, ACTION_SHOW_GUI, ACTION_STOP, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU, KEY_BUTTON_BACK]:
  956. subprocess.Popen('xdotool key alt+F4', shell=True)
  957. self.close()
  958. elif action==ACTION_SELECT_ITEM:
  959. subprocess.Popen('xdotool key Return', shell=True)
  960. elif action==ACTION_MOVE_LEFT:
  961. subprocess.Popen('xdotool key Left', shell=True)
  962. elif action==ACTION_MOVE_RIGHT:
  963. subprocess.Popen('xdotool key Right', shell=True)
  964. elif action==ACTION_MOVE_UP:
  965. subprocess.Popen('xdotool key Up', shell=True)
  966. elif action==ACTION_MOVE_DOWN:
  967. subprocess.Popen('xdotool key Down', shell=True)
  968. else:
  969. self.close()
  970. elif osOSX:
  971. proc = subprocess.Popen('/bin/ps ax', shell=True, stdout=subprocess.PIPE)
  972. procAll = ""
  973. for line in proc.stdout:
  974. procAll+=line
  975. if "chrome" in procAll:
  976. if action in [ACTION_SHOW_INFO, ACTION_SHOW_GUI, ACTION_STOP, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU, KEY_BUTTON_BACK]:
  977. subprocess.Popen('cliclick kd:alt', shell=True)
  978. subprocess.Popen('cliclick kp:f4', shell=True)
  979. self.close()
  980. elif action==ACTION_SELECT_ITEM:
  981. subprocess.Popen('cliclick kp:return', shell=True)
  982. elif action==ACTION_MOVE_LEFT:
  983. subprocess.Popen('cliclick kp:arrow-left', shell=True)
  984. elif action==ACTION_MOVE_RIGHT:
  985. subprocess.Popen('cliclick kp:arrow-right', shell=True)
  986. elif action==ACTION_MOVE_UP:
  987. subprocess.Popen('cliclick kp:arrow-up', shell=True)
  988. elif action==ACTION_MOVE_DOWN:
  989. subprocess.Popen('cliclick kp:arrow-down', shell=True)
  990. else:
  991. self.close()
  992.  
  993.  
  994. params = parameters_string_to_dict(sys.argv[2])
  995. mode = urllib.unquote_plus(params.get('mode', ''))
  996. url = urllib.unquote_plus(params.get('url', ''))
  997. thumb = urllib.unquote_plus(params.get('thumb', ''))
  998. name = urllib.unquote_plus(params.get('name', ''))
  999. season = urllib.unquote_plus(params.get('season', ''))
  1000. seriesID = urllib.unquote_plus(params.get('seriesID', ''))
  1001. type = urllib.unquote_plus(params.get('type', ''))
  1002.  
  1003. if mode == 'main':
  1004. main(type)
  1005. elif mode == 'wiHome':
  1006. wiHome(type)
  1007. elif mode == 'listVideos':
  1008. listVideos(url, type)
  1009. elif mode == 'listSliderVideos':
  1010. listSliderVideos(url, type)
  1011. elif mode == 'listSearchVideos':
  1012. listSearchVideos(url, type)
  1013. elif mode == 'addToQueue':
  1014. addToQueue(url)
  1015. elif mode == 'removeFromQueue':
  1016. removeFromQueue(url)
  1017. elif mode == 'playVideo':
  1018. playVideo(url)
  1019. elif mode == 'playVideoMain':
  1020. if seriesID == '':
  1021. playVideoMain(url)
  1022. else:
  1023. playVideoMain(url, seriesID)
  1024. elif mode == 'search':
  1025. search(type)
  1026. elif mode == 'login':
  1027. login()
  1028. elif mode == 'chooseProfile':
  1029. chooseProfile()
  1030. elif mode == 'listGenres':
  1031. listGenres(url, type)
  1032. elif mode == 'listTvGenres':
  1033. listTvGenres(type)
  1034. elif mode == 'listViewingActivity':
  1035. listViewingActivity(type)
  1036. elif mode == 'listSeasons':
  1037. listSeasons(name, url, thumb)
  1038. elif mode == 'listEpisodes':
  1039. listEpisodes(seriesID, url)
  1040. elif mode == 'configureUtility':
  1041. configureUtility()
  1042. elif mode == 'deleteCookies':
  1043. deleteCookies()
  1044. elif mode == 'deleteCache':
  1045. deleteCache()
  1046. elif mode == 'resetAddon':
  1047. resetAddon()
  1048. elif mode == 'playTrailer':
  1049. playTrailer(url)
  1050. elif mode == 'addMyListToLibrary':
  1051. addMyListToLibrary()
  1052. elif mode == 'addMovieToLibrary':
  1053. addMovieToLibrary(url, name)
  1054. elif mode == 'addSeriesToLibrary':
  1055. addSeriesToLibrary(seriesID, name, url)
  1056. else:
  1057. index()
RAW Paste Data