Advertisement
Guest User

Trakt Utilities

a guest
Nov 12th, 2011
296
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 34.90 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. #
  3.  
  4. import os, sys
  5. import xbmc,xbmcaddon,xbmcgui
  6. import time, socket
  7.  
  8. try: import simplejson as json
  9. except ImportError: import json
  10.  
  11. from nbhttpconnection import *
  12.  
  13. import urllib, re
  14.  
  15. try:
  16.     # Python 3.0 +
  17.     import http.client as httplib
  18. except ImportError:
  19.     # Python 2.7 and earlier
  20.     import httplib
  21.  
  22. try:
  23.   # Python 2.6 +
  24.   from hashlib import sha as sha
  25. except ImportError:
  26.   # Python 2.5 and earlier
  27.   import sha
  28.  
  29. __author__ = "Ralph-Gordon Paul, Adrian Cowan"
  30. __credits__ = ["Ralph-Gordon Paul", "Adrian Cowan", "Justin Nemeth",  "Sean Rudford"]
  31. __license__ = "GPL"
  32. __maintainer__ = "Ralph-Gordon Paul"
  33. __email__ = "ralph-gordon.paul@uni-duesseldorf.de"
  34. __status__ = "Production"
  35.  
  36. # read settings
  37. __settings__ = xbmcaddon.Addon( "script.TraktUtilities" )
  38. __language__ = __settings__.getLocalizedString
  39.  
  40. apikey = '48dfcb4813134da82152984e8c4f329bc8b8b46a'
  41. username = __settings__.getSetting("username")
  42. pwd = sha.new(__settings__.getSetting("password")).hexdigest()
  43. debug = __settings__.getSetting( "debug" )
  44.  
  45. headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
  46.  
  47. def Debug(msg, force=False):
  48.     if (debug == 'true' or force):
  49.         try:
  50.             print "Trakt Utilities: " + msg
  51.         except UnicodeEncodeError:
  52.             print "Trakt Utilities: " + msg.encode( "utf-8", "ignore" )
  53.  
  54. def notification( header, message, time=5000, icon=__settings__.getAddonInfo( "icon" ) ):
  55.     xbmc.executebuiltin( "XBMC.Notification(%s,%s,%i,%s)" % ( header, message, time, icon ) )
  56.  
  57. def checkSettings(daemon=False):
  58.     if username == "":
  59.         if daemon:
  60.             notification("Trakt Utilities", __language__(1106).encode( "utf-8", "ignore" )) # please enter your Username and Password in settings
  61.         else:
  62.             xbmcgui.Dialog().ok("Trakt Utilities", __language__(1106).encode( "utf-8", "ignore" )) # please enter your Username and Password in settings
  63.             __settings__.openSettings()
  64.         return False
  65.     elif __settings__.getSetting("password") == "":
  66.         if daemon:
  67.             notification("Trakt Utilities", __language__(1107).encode( "utf-8", "ignore" )) # please enter your Password in settings
  68.         else:
  69.             xbmcgui.Dialog().ok("Trakt Utilities", __language__(1107).encode( "utf-8", "ignore" )) # please enter your Password in settings
  70.             __settings__.openSettings()
  71.         return False
  72.    
  73.     data = traktJsonRequest('POST', '/account/test/%%API_KEY%%', silent=True)
  74.     if data == None: #Incorrect trakt login details
  75.         if daemon:
  76.             notification("Trakt Utilities", __language__(1110).encode( "utf-8", "ignore" )) # please enter your Password in settings
  77.         else:
  78.             xbmcgui.Dialog().ok("Trakt Utilities", __language__(1110).encode( "utf-8", "ignore" )) # please enter your Password in settings
  79.             __settings__.openSettings()
  80.         return False
  81.        
  82.     return True
  83.  
  84. # SQL string quote escaper
  85. def xcp(s):
  86.     return re.sub('''(['])''', r"''", str(s))
  87.  
  88. # make a httpapi based XBMC db query (get data)
  89. def xbmcHttpapiQuery(query):
  90.     Debug("[httpapi-sql] query: "+query)
  91.    
  92.     xml_data = xbmc.executehttpapi( "QueryVideoDatabase(%s)" % urllib.quote_plus(query), )
  93.     match = re.findall( "<field>((?:[^<]|<(?!/))*)</field>", xml_data,)
  94.    
  95.     Debug("[httpapi-sql] responce: "+xml_data)
  96.     Debug("[httpapi-sql] matches: "+str(match))
  97.    
  98.     return match
  99.  
  100. # execute a httpapi based XBMC db query (set data)
  101. def xbmcHttpapiExec(query):
  102.     xml_data = xbmc.executehttpapi( "ExecVideoDatabase(%s)" % urllib.quote_plus(query), )
  103.     return xml_data
  104.  
  105. # get a connection to trakt
  106. def getTraktConnection():
  107.     try:
  108.         conn = NBHTTPConnection('api.trakt.tv')
  109.     except socket.timeout:
  110.         Debug("getTraktConnection: can't connect to trakt - timeout")
  111.         notification("Trakt Utilities", __language__(1108).encode( "utf-8", "ignore" ) + ": timeout") # can't connect to trakt
  112.         return None
  113.     return conn
  114.    
  115. # make a JSON api request to trakt
  116. # method: http method (GET or POST)
  117. # req: REST request (ie '/user/library/movies/all.json/%%API_KEY%%/%%USERNAME%%')
  118. # args: arguments to be passed by POST JSON (only applicable to POST requests), default:{}
  119. # returnStatus: when unset or set to false the function returns None apon error and shows a notification,
  120. #   when set to true the function returns the status and errors in ['error'] as given to it and doesn't show the notification,
  121. #   use to customise error notifications
  122. # anon: anonymous (dont send username/password), default:False
  123. # connection: default it to make a new connection but if you want to keep the same one alive pass it here
  124. # silent: default is False, when true it disable any error notifications (but not debug messages)
  125. # passVersions: default is False, when true it passes extra version information to trakt to help debug problems
  126. def traktJsonRequest(method, req, args={}, returnStatus=False, anon=False, conn=False, silent=False, passVersions=False):
  127.     closeConnection = False
  128.     if conn == False:
  129.         conn = getTraktConnection()
  130.         closeConnection = True
  131.     if conn == None:
  132.         if returnStatus:
  133.             data = {}
  134.             data['status'] = 'failure'
  135.             data['error'] = 'Unable to connect to trakt'
  136.             return data
  137.         return None
  138.  
  139.     try:
  140.         req = req.replace("%%API_KEY%%",apikey)
  141.         req = req.replace("%%USERNAME%%",username)
  142.         if method == 'POST':
  143.             if not anon:
  144.                 args['username'] = username
  145.                 args['password'] = pwd
  146.             if passVersions:
  147.                 args['plugin_version'] = __settings__.getAddonInfo("version")
  148.                 args['media_center'] = 'xbmc'
  149.                 args['media_center_version'] = xbmc.getInfoLabel("system.buildversion")
  150.                 args['media_center_date'] = xbmc.getInfoLabel("system.builddate")
  151.             jdata = json.dumps(args)
  152.             conn.request('POST', req, jdata)
  153.         elif method == 'GET':
  154.             conn.request('GET', req)
  155.         else:
  156.             return None
  157.         Debug("trakt json url: "+req)
  158.     except socket.error:
  159.         Debug("traktQuery: can't connect to trakt")
  160.         if not silent: notification("Trakt Utilities", __language__(1108).encode( "utf-8", "ignore" )) # can't connect to trakt
  161.         if returnStatus:
  162.             data = {}
  163.             data['status'] = 'failure'
  164.             data['error'] = 'Socket error, unable to connect to trakt'
  165.             return data;
  166.         return None
  167.      
  168.     conn.go()
  169.    
  170.     while True:
  171.         if xbmc.abortRequested:
  172.             Debug("Broke loop due to abort")
  173.             if returnStatus:
  174.                 data = {}
  175.                 data['status'] = 'failure'
  176.                 data['error'] = 'Abort requested, not waiting for responce'
  177.                 return data;
  178.             return None
  179.         if conn.hasResult():
  180.             break
  181.         time.sleep(0.1)
  182.    
  183.     response = conn.getResult()
  184.    
  185.     try:
  186.         raw = response.read()
  187.         data = json.loads(raw)
  188.     except ValueError:
  189.         Debug("traktQuery: Bad JSON responce: "+raw)
  190.         if returnStatus:
  191.             data = {}
  192.             data['status'] = 'failure'
  193.             data['error'] = 'Bad responce from trakt'
  194.             return data
  195.         if not silent: notification("Trakt Utilities", __language__(1109).encode( "utf-8", "ignore" ) + ": Bad responce from trakt") # Error
  196.         if closeConnection:
  197.             conn.close()
  198.         return None
  199.  
  200.     if closeConnection:
  201.         conn.close()
  202.    
  203.     if 'status' in data:
  204.         if data['status'] == 'failure':
  205.             Debug("traktQuery: Error: " + str(data['error']))
  206.             if returnStatus:
  207.                 return data;
  208.             if not silent: notification("Trakt Utilities", __language__(1109).encode( "utf-8", "ignore" ) + ": " + str(data['error'])) # Error
  209.             return None
  210.    
  211.     return data
  212.    
  213. # get movies from trakt server
  214. def getMoviesFromTrakt(daemon=False):
  215.     data = traktJsonRequest('POST', '/user/library/movies/all.json/%%API_KEY%%/%%USERNAME%%')
  216.     if data == None:
  217.         Debug("Error in request from 'getMoviesFromTrakt()'")
  218.     return data
  219.  
  220. # get movie that are listed as in the users collection from trakt server
  221. def getMovieCollectionFromTrakt(daemon=False):
  222.     data = traktJsonRequest('POST', '/user/library/movies/collection.json/%%API_KEY%%/%%USERNAME%%')
  223.     if data == None:
  224.         Debug("Error in request from 'getMovieCollectionFromTrakt()'")
  225.     return data
  226.  
  227. # get easy access to movie by imdb_id
  228. def traktMovieListByImdbID(data):
  229.     trakt_movies = {}
  230.  
  231.     for i in range(0, len(data)):
  232.         if data[i]['imdb_id'] == "": continue
  233.         trakt_movies[data[i]['imdb_id']] = data[i]
  234.        
  235.     return trakt_movies
  236.  
  237. # get easy access to tvshow by tvdb_id
  238. def traktShowListByTvdbID(data):
  239.     trakt_tvshows = {}
  240.  
  241.     for i in range(0, len(data)):
  242.         trakt_tvshows[data[i]['tvdb_id']] = data[i]
  243.        
  244.     return trakt_tvshows
  245.  
  246. # get seen tvshows from trakt server
  247. def getWatchedTVShowsFromTrakt(daemon=False):
  248.     data = traktJsonRequest('POST', '/user/library/shows/watched.json/%%API_KEY%%/%%USERNAME%%')
  249.     if data == None:
  250.         Debug("Error in request from 'getWatchedTVShowsFromTrakt()'")
  251.     return data
  252.  
  253. # set episodes seen on trakt
  254. def setEpisodesSeenOnTrakt(tvdb_id, title, year, episodes):
  255.     data = traktJsonRequest('POST', '/show/episode/seen/%%API_KEY%%', {'tvdb_id': tvdb_id, 'title': title, 'year': year, 'episodes': episodes})
  256.     if data == None:
  257.         Debug("Error in request from 'setEpisodeSeenOnTrakt()'")
  258.     return data
  259.  
  260. # set episodes unseen on trakt
  261. def setEpisodesUnseenOnTrakt(tvdb_id, title, year, episodes):
  262.     data = traktJsonRequest('POST', '/show/episode/unseen/%%API_KEY%%', {'tvdb_id': tvdb_id, 'title': title, 'year': year, 'episodes': episodes})
  263.     if data == None:
  264.         Debug("Error in request from 'setEpisodesUnseenOnTrakt()'")
  265.     return data
  266.  
  267. # set movies seen on trakt
  268. #  - movies, required fields are 'plays', 'last_played' and 'title', 'year' or optionally 'imdb_id'
  269. def setMoviesSeenOnTrakt(movies):
  270.     data = traktJsonRequest('POST', '/movie/seen/%%API_KEY%%', {'movies': movies})
  271.     if data == None:
  272.         Debug("Error in request from 'setMoviesSeenOnTrakt()'")
  273.     return data
  274.  
  275. # set movies unseen on trakt
  276. #  - movies, required fields are 'plays', 'last_played' and 'title', 'year' or optionally 'imdb_id'
  277. def setMoviesUnseenOnTrakt(movies):
  278.     data = traktJsonRequest('POST', '/movie/unseen/%%API_KEY%%', {'movies': movies})
  279.     if data == None:
  280.         Debug("Error in request from 'setMoviesUnseenOnTrakt()'")
  281.     return data
  282.  
  283. # get tvshow collection from trakt server
  284. def getTVShowCollectionFromTrakt(daemon=False):
  285.     data = traktJsonRequest('POST', '/user/library/shows/collection.json/%%API_KEY%%/%%USERNAME%%')
  286.     if data == None:
  287.         Debug("Error in request from 'getTVShowCollectionFromTrakt()'")
  288.     return data
  289.    
  290. # get tvshows from XBMC
  291. def getTVShowsFromXBMC():
  292.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetTVShows','params':{'properties': ['title', 'year', 'imdbnumber', 'playcount']}, 'id': 1})
  293.    
  294.     result = xbmc.executeJSONRPC(rpccmd)
  295.     result = json.loads(result)
  296.    
  297.     # check for error
  298.     try:
  299.         error = result['error']
  300.         Debug("getTVShowsFromXBMC: " + str(error))
  301.         return None
  302.     except KeyError:
  303.         pass # no error
  304.    
  305.     try:
  306.         return result['result']
  307.     except KeyError:
  308.         Debug("getTVShowsFromXBMC: KeyError: result['result']")
  309.         return None
  310.    
  311. # get seasons for a given tvshow from XBMC
  312. def getSeasonsFromXBMC(tvshow):
  313.     Debug("getSeasonsFromXBMC: "+str(tvshow))
  314.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetSeasons','params':{'tvshowid': tvshow['tvshowid']}, 'id': 1})
  315.    
  316.     result = xbmc.executeJSONRPC(rpccmd)
  317.     result = json.loads(result)
  318.    
  319.     # check for error
  320.     try:
  321.         error = result['error']
  322.         Debug("getSeasonsFromXBMC: " + str(error))
  323.         return None
  324.     except KeyError:
  325.         pass # no error
  326.  
  327.     try:
  328.         return result['result']
  329.     except KeyError:
  330.         Debug("getSeasonsFromXBMC: KeyError: result['result']")
  331.         return None
  332.    
  333. # get episodes for a given tvshow / season from XBMC
  334. def getEpisodesFromXBMC(tvshow, season):
  335.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetEpisodes','params':{'tvshowid': tvshow['tvshowid'], 'season': season, 'properties': ['playcount', 'episode']}, 'id': 1})
  336.    
  337.     result = xbmc.executeJSONRPC(rpccmd)
  338.     result = json.loads(result)
  339.  
  340.     # check for error
  341.     try:
  342.         error = result['error']
  343.         Debug("getEpisodesFromXBMC: " + str(error))
  344.         return None
  345.     except KeyError:
  346.         pass # no error
  347.  
  348.     try:
  349.         return result['result']
  350.     except KeyError:
  351.         Debug("getEpisodesFromXBMC: KeyError: result['result']")
  352.         return None
  353.  
  354. # get a single episode from xbmc given the id
  355. def getEpisodeDetailsFromXbmc(libraryId, fields):
  356.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetEpisodeDetails','params':{'episodeid': libraryId, 'properties': fields}, 'id': 1})
  357.    
  358.     result = xbmc.executeJSONRPC(rpccmd)
  359.     result = json.loads(result)
  360.  
  361.     # check for error
  362.     try:
  363.         error = result['error']
  364.         Debug("getEpisodeDetailsFromXbmc: " + str(error))
  365.         return None
  366.     except KeyError:
  367.         pass # no error
  368.  
  369.     try:
  370.         return result['result']['episodedetails']
  371.     except KeyError:
  372.         Debug("getEpisodeDetailsFromXbmc: KeyError: result['result']['episodedetails']")
  373.         return None
  374.  
  375. # get movies from XBMC
  376. def getMoviesFromXBMC():
  377.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetMovies','params':{'properties': ['title', 'year', 'originaltitle', 'imdbnumber', 'playcount', 'lastplayed']}, 'id': 1})
  378.  
  379.     result = xbmc.executeJSONRPC(rpccmd)
  380.     result = json.loads(result)
  381.    
  382.     # check for error
  383.     try:
  384.         error = result['error']
  385.         Debug("getMoviesFromXBMC: " + str(error))
  386.         return None
  387.     except KeyError:
  388.         pass # no error
  389.    
  390.     try:
  391.         return result['result']['movies']
  392.         Debug("getMoviesFromXBMC: KeyError: result['result']['movies']")
  393.     except KeyError:
  394.         return None
  395.  
  396. # get a single movie from xbmc given the id
  397. def getMovieDetailsFromXbmc(libraryId, fields):
  398.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'VideoLibrary.GetMovieDetails','params':{'movieid': libraryId, 'properties': fields}, 'id': 1})
  399.    
  400.     result = xbmc.executeJSONRPC(rpccmd)
  401.     result = json.loads(result)
  402.  
  403.     # check for error
  404.     try:
  405.         error = result['error']
  406.         Debug("getMovieDetailsFromXbmc: " + str(error))
  407.         return None
  408.     except KeyError:
  409.         pass # no error
  410.  
  411.     try:
  412.         return result['result']['moviedetails']
  413.     except KeyError:
  414.         Debug("getMovieDetailsFromXbmc: KeyError: result['result']['moviedetails']")
  415.         return None
  416.  
  417. # sets the playcount of a given movie by imdbid
  418. def setXBMCMoviePlaycount(imdb_id, playcount):
  419.  
  420.     # httpapi till jsonrpc supports playcount update
  421.     # c09 => IMDB ID
  422.     match = xbmcHttpapiQuery(
  423.     "SELECT movie.idFile FROM movie"+
  424.     " WHERE movie.c09='%(imdb_id)s'" % {'imdb_id':xcp(imdb_id)})
  425.    
  426.     if not match:
  427.         #add error message here
  428.         return
  429.    
  430.     result = xbmcHttpapiExec(
  431.     "UPDATE files"+
  432.     " SET playcount=%(playcount)d" % {'playcount':int(playcount)}+
  433.     " WHERE idFile=%(idFile)s" % {'idFile':xcp(match[0])})
  434.    
  435.     Debug("xml answer: " + str(result))
  436.  
  437. # sets the playcount of a given episode by tvdb_id
  438. def setXBMCEpisodePlaycount(tvdb_id, seasonid, episodeid, playcount):
  439.     # httpapi till jsonrpc supports playcount update
  440.     # select tvshow by tvdb_id # c12 => TVDB ID # c00 = title
  441.     match = xbmcHttpapiQuery(
  442.     "SELECT tvshow.idShow, tvshow.c00 FROM tvshow"+
  443.     " WHERE tvshow.c12='%(tvdb_id)s'" % {'tvdb_id':xcp(tvdb_id)})
  444.    
  445.     if match:
  446.         Debug("TV Show: " + match[1] + " idShow: " + str(match[0]) + " season: " + str(seasonid) + " episode: " + str(episodeid))
  447.  
  448.         # select episode table by idShow
  449.         match = xbmcHttpapiQuery(
  450.         "SELECT tvshowlinkepisode.idEpisode FROM tvshowlinkepisode"+
  451.         " WHERE tvshowlinkepisode.idShow=%(idShow)s" % {'idShow':xcp(match[0])})
  452.        
  453.         for idEpisode in match:
  454.             # get idfile from episode table # c12 = season, c13 = episode
  455.             match2 = xbmcHttpapiQuery(
  456.             "SELECT episode.idFile FROM episode"+
  457.             " WHERE episode.idEpisode=%(idEpisode)d" % {'idEpisode':int(idEpisode)}+
  458.             " AND episode.c12='%(seasonid)s'" % {'seasonid':xcp(seasonid)}+
  459.             " AND episode.c13='%(episodeid)s'" % {'episodeid':xcp(episodeid)})
  460.            
  461.             if match2:
  462.                 for idFile in match2:
  463.                     Debug("idFile: " + str(idFile) + " setting playcount...")
  464.                     responce = xbmcHttpapiExec(
  465.                     "UPDATE files"+
  466.                     " SET playcount=%(playcount)s" % {'playcount':xcp(playcount)}+
  467.                     " WHERE idFile=%(idFile)s" % {'idFile':xcp(idFile)})
  468.                    
  469.                     Debug("xml answer: " + str(responce))
  470.     else:
  471.         Debug("setXBMCEpisodePlaycount: no tv show found for tvdb id: " + str(tvdb_id))
  472.    
  473. # get current video being played from XBMC
  474. def getCurrentPlayingVideoFromXBMC():
  475.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'Player.GetActivePlayers','params':{}, 'id': 1})
  476.     result = xbmc.executeJSONRPC(rpccmd)
  477.     result = json.loads(result)
  478.     # check for error
  479.     try:
  480.         error = result['error']
  481.         Debug("[Util] getCurrentPlayingVideoFromXBMC: " + str(error))
  482.         return None
  483.     except KeyError:
  484.         pass # no error
  485.    
  486.     try:
  487.         for player in result['result']:
  488.             if player['type'] == 'video':
  489.                 rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'Player.GetProperties','params':{'playerid': player['playerid'], 'properties':['playlistid', 'position']}, 'id': 1})
  490.                 result2 = xbmc.executeJSONRPC(rpccmd)
  491.                 result2 = json.loads(result2)
  492.                 # check for error
  493.                 try:
  494.                     error = result2['error']
  495.                     Debug("[Util] getCurrentPlayingVideoFromXBMC, Player.GetProperties: " + str(error))
  496.                     return None
  497.                 except KeyError:
  498.                     pass # no error
  499.                 playlistid = result2['result']['playlistid']
  500.                 position = result2['result']['position']
  501.                
  502.                 rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'Playlist.GetItems','params':{'playlistid': playlistid}, 'id': 1})
  503.                 result2 = xbmc.executeJSONRPC(rpccmd)
  504.                 result2 = json.loads(result2)
  505.                 # check for error
  506.                 try:
  507.                     error = result2['error']
  508.                     Debug("[Util] getCurrentPlayingVideoFromXBMC, Playlist.GetItems: " + str(error))
  509.                     return None
  510.                 except KeyError:
  511.                     pass # no error
  512.                 Debug("Current playlist: "+str(result2['result']))
  513.                
  514.                 return result2['result'][position]
  515.         Debug("[Util] getCurrentPlayingVideoFromXBMC: No current video player")
  516.         return None
  517.     except KeyError:
  518.         Debug("[Util] getCurrentPlayingVideoFromXBMC: KeyError")
  519.         return None
  520.        
  521. # get the length of the current video playlist being played from XBMC
  522. def getPlaylistLengthFromXBMCPlayer(playerid):
  523.     if playerid == -1:
  524.         return 1 #Default player (-1) can't be checked properly
  525.     if playerid < 0 or playerid > 2:
  526.         Debug("[Util] getPlaylistLengthFromXBMCPlayer, invalid playerid: "+str(playerid))
  527.         return 0
  528.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'Player.GetProperties','params':{'playerid': playerid, 'properties':['playlistid']}, 'id': 1})
  529.     result = xbmc.executeJSONRPC(rpccmd)
  530.     result = json.loads(result)
  531.     # check for error
  532.     try:
  533.         error = result['error']
  534.         Debug("[Util] getPlaylistLengthFromXBMCPlayer, Player.GetProperties: " + str(error))
  535.         return 0
  536.     except KeyError:
  537.         pass # no error
  538.     playlistid = result['result']['playlistid']
  539.    
  540.     rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'Playlist.GetProperties','params':{'playlistid': playlistid, 'properties': ['size']}, 'id': 1})
  541.     result = xbmc.executeJSONRPC(rpccmd)
  542.     result = json.loads(result)
  543.     # check for error
  544.     try:
  545.         error = result['error']
  546.         Debug("[Util] getPlaylistLengthFromXBMCPlayer, Playlist.GetProperties: " + str(error))
  547.         return 0
  548.     except KeyError:
  549.         pass # no error
  550.    
  551.     return result['result']['size']
  552.  
  553. def getMovieIdFromXBMC(imdb_id, title):
  554.     # httpapi till jsonrpc supports searching for a single movie
  555.     # Get id of movie by movies IMDB
  556.     Debug("Searching for movie: "+imdb_id+", "+title)
  557.    
  558.     match = xbmcHttpapiQuery(
  559.     " SELECT idMovie FROM movie"+
  560.     "  WHERE c09='%(imdb_id)s'" % {'imdb_id':imdb_id}+
  561.     " UNION"+
  562.     " SELECT idMovie FROM movie"+
  563.     "  WHERE upper(c00)='%(title)s'" % {'title':xcp(title.upper())}+
  564.     " LIMIT 1")
  565.    
  566.     if not match:
  567.         Debug("getMovieIdFromXBMC: cannot find movie in database")
  568.         return -1
  569.        
  570.     return match[0]
  571.  
  572. def getShowIdFromXBMC(tvdb_id, title):
  573.     # httpapi till jsonrpc supports searching for a single show
  574.     # Get id of show by shows tvdb id
  575.    
  576.     Debug("Searching for show: "+str(tvdb_id)+", "+title)
  577.    
  578.     match = xbmcHttpapiQuery(
  579.     " SELECT idShow FROM tvshow"+
  580.     "  WHERE c12='%(tvdb_id)s'" % {'tvdb_id':xcp(tvdb_id)}+
  581.     " UNION"+
  582.     " SELECT idShow FROM tvshow"+
  583.     "  WHERE upper(c00)='%(title)s'" % {'title':xcp(title.upper())}+
  584.     " LIMIT 1")
  585.    
  586.     if not match:
  587.         Debug("getShowIdFromXBMC: cannot find movie in database")
  588.         return -1
  589.        
  590.     return match[0]
  591.  
  592. # returns list of movies from watchlist
  593. def getWatchlistMoviesFromTrakt():
  594.     data = traktJsonRequest('POST', '/user/watchlist/movies.json/%%API_KEY%%/%%USERNAME%%')
  595.     if data == None:
  596.         Debug("Error in request from 'getWatchlistMoviesFromTrakt()'")
  597.     return data
  598.  
  599. # returns list of tv shows from watchlist
  600. def getWatchlistTVShowsFromTrakt():
  601.     data = traktJsonRequest('POST', '/user/watchlist/shows.json/%%API_KEY%%/%%USERNAME%%')
  602.     if data == None:
  603.         Debug("Error in request from 'getWatchlistTVShowsFromTrakt()'")
  604.     return data
  605.  
  606. # add an array of movies to the watch-list
  607. def addMoviesToWatchlist(data):
  608.     movies = []
  609.     for item in data:
  610.         movie = {}
  611.         if "imdb_id" in item:
  612.             movie["imdb_id"] = item["imdb_id"]
  613.         if "tmdb_id" in item:
  614.             movie["tmdb_id"] = item["tmdb_id"]
  615.         if "title" in item:
  616.             movie["title"] = item["title"]
  617.         if "year" in item:
  618.             movie["year"] = item["year"]
  619.         movies.append(movie)
  620.    
  621.     data = traktJsonRequest('POST', '/movie/watchlist/%%API_KEY%%', {"movies":movies})
  622.     if data == None:
  623.         Debug("Error in request from 'addMoviesToWatchlist()'")
  624.     return data
  625.  
  626. # remove an array of movies from the watch-list
  627. def removeMoviesFromWatchlist(data):
  628.     movies = []
  629.     for item in data:
  630.         movie = {}
  631.         if "imdb_id" in item:
  632.             movie["imdb_id"] = item["imdb_id"]
  633.         if "tmdb_id" in item:
  634.             movie["tmdb_id"] = item["tmdb_id"]
  635.         if "title" in item:
  636.             movie["title"] = item["title"]
  637.         if "year" in item:
  638.             movie["year"] = item["year"]
  639.         movies.append(movie)
  640.    
  641.     data = traktJsonRequest('POST', '/movie/unwatchlist/%%API_KEY%%', {"movies":movies})
  642.     if data == None:
  643.         Debug("Error in request from 'removeMoviesFromWatchlist()'")
  644.     return data
  645.  
  646. # add an array of tv shows to the watch-list
  647. def addTVShowsToWatchlist(data):
  648.     shows = []
  649.     for item in data:
  650.         show = {}
  651.         if "tvdb_id" in item:
  652.             show["tvdb_id"] = item["tvdb_id"]
  653.         if "imdb_id" in item:
  654.             show["tmdb_id"] = item["imdb_id"]
  655.         if "title" in item:
  656.             show["title"] = item["title"]
  657.         if "year" in item:
  658.             show["year"] = item["year"]
  659.         shows.append(show)
  660.    
  661.     data = traktJsonRequest('POST', '/show/watchlist/%%API_KEY%%', {"shows":shows})
  662.     if data == None:
  663.         Debug("Error in request from 'addMoviesToWatchlist()'")
  664.     return data
  665.  
  666. # remove an array of tv shows from the watch-list
  667. def removeTVShowsFromWatchlist(data):
  668.     shows = []
  669.     for item in data:
  670.         show = {}
  671.         if "tvdb_id" in item:
  672.             show["tvdb_id"] = item["tvdb_id"]
  673.         if "imdb_id" in item:
  674.             show["imdb_id"] = item["imdb_id"]
  675.         if "title" in item:
  676.             show["title"] = item["title"]
  677.         if "year" in item:
  678.             show["year"] = item["year"]
  679.         shows.append(show)
  680.    
  681.     data = traktJsonRequest('POST', '/show/unwatchlist/%%API_KEY%%', {"shows":shows})
  682.     if data == None:
  683.         Debug("Error in request from 'removeMoviesFromWatchlist()'")
  684.     return data
  685.  
  686. #Set the rating for a movie on trakt, rating: "hate" = Weak sauce, "love" = Totaly ninja
  687. def rateMovieOnTrakt(imdbid, title, year, rating):
  688.     if not (rating in ("love", "hate", "unrate")):
  689.         #add error message
  690.         return
  691.    
  692.     Debug("Rating movie:" + rating)
  693.    
  694.     data = traktJsonRequest('POST', '/rate/movie/%%API_KEY%%', {'imdb_id': imdbid, 'title': title, 'year': year, 'rating': rating})
  695.     if data == None:
  696.         Debug("Error in request from 'rateMovieOnTrakt()'")
  697.    
  698.     if (rating == "unrate"):
  699.         notification("Trakt Utilities", __language__(1166).encode( "utf-8", "ignore" )) # Rating removed successfully
  700.     else :
  701.         notification("Trakt Utilities", __language__(1167).encode( "utf-8", "ignore" )) # Rating submitted successfully
  702.    
  703.     return data
  704.  
  705. #Get the rating for a movie from trakt
  706. def getMovieRatingFromTrakt(imdbid, title, year):
  707.     if imdbid == "" or imdbid == None:
  708.         return None #would be nice to be smarter in this situation
  709.    
  710.     data = traktJsonRequest('POST', '/movie/summary.json/%%API_KEY%%/'+str(imdbid))
  711.     if data == None:
  712.         Debug("Error in request from 'getMovieRatingFromTrakt()'")
  713.         return None
  714.        
  715.     if 'rating' in data:
  716.         return data['rating']
  717.        
  718.     print data
  719.     Debug("Error in request from 'getMovieRatingFromTrakt()'")
  720.     return None
  721.  
  722. #Set the rating for a tv episode on trakt, rating: "hate" = Weak sauce, "love" = Totaly ninja
  723. def rateEpisodeOnTrakt(tvdbid, title, year, season, episode, rating):
  724.     if not (rating in ("love", "hate", "unrate")):
  725.         #add error message
  726.         return
  727.    
  728.     Debug("Rating episode:" + rating)
  729.    
  730.     data = traktJsonRequest('POST', '/rate/episode/%%API_KEY%%', {'tvdb_id': tvdbid, 'title': title, 'year': year, 'season': season, 'episode': episode, 'rating': rating})
  731.     if data == None:
  732.         Debug("Error in request from 'rateEpisodeOnTrakt()'")
  733.    
  734.     if (rating == "unrate"):
  735.         notification("Trakt Utilities", __language__(1166).encode( "utf-8", "ignore" )) # Rating removed successfully
  736.     else :
  737.         notification("Trakt Utilities", __language__(1167).encode( "utf-8", "ignore" )) # Rating submitted successfully
  738.    
  739.     return data
  740.    
  741. #Get the rating for a tv episode from trakt
  742. def getEpisodeRatingFromTrakt(tvdbid, title, year, season, episode):
  743.     if tvdbid == "" or tvdbid == None:
  744.         return None #would be nice to be smarter in this situation
  745.    
  746.     data = traktJsonRequest('POST', '/show/episode/summary.json/%%API_KEY%%/'+str(tvdbid)+"/"+season+"/"+episode)
  747.     if data == None:
  748.         Debug("Error in request from 'getEpisodeRatingFromTrakt()'")
  749.         return None
  750.        
  751.     if 'rating' in data:
  752.         return data['rating']
  753.        
  754.     print data
  755.     Debug("Error in request from 'getEpisodeRatingFromTrakt()'")
  756.     return None
  757.  
  758. #Set the rating for a tv show on trakt, rating: "hate" = Weak sauce, "love" = Totaly ninja
  759. def rateShowOnTrakt(tvdbid, title, year, rating):
  760.     if not (rating in ("love", "hate", "unrate")):
  761.         #add error message
  762.         return
  763.    
  764.     Debug("Rating show:" + rating)
  765.    
  766.     data = traktJsonRequest('POST', '/rate/show/%%API_KEY%%', {'tvdb_id': tvdbid, 'title': title, 'year': year, 'rating': rating})
  767.     if data == None:
  768.         Debug("Error in request from 'rateShowOnTrakt()'")
  769.    
  770.     if (rating == "unrate"):
  771.         notification("Trakt Utilities", __language__(1166).encode( "utf-8", "ignore" )) # Rating removed successfully
  772.     else :
  773.         notification("Trakt Utilities", __language__(1167).encode( "utf-8", "ignore" )) # Rating submitted successfully
  774.    
  775.     return data
  776.  
  777. #Get the rating for a tv show from trakt
  778. def getShowRatingFromTrakt(tvdbid, title, year):
  779.     if tvdbid == "" or tvdbid == None:
  780.         return None #would be nice to be smarter in this situation
  781.    
  782.     data = traktJsonRequest('POST', '/show/summary.json/%%API_KEY%%/'+str(tvdbid))
  783.     if data == None:
  784.         Debug("Error in request from 'getShowRatingFromTrakt()'")
  785.         return None
  786.        
  787.     if 'rating' in data:
  788.         return data['rating']
  789.        
  790.     print data
  791.     Debug("Error in request from 'getShowRatingFromTrakt()'")
  792.     return None
  793.  
  794. def getRecommendedMoviesFromTrakt():
  795.     data = traktJsonRequest('POST', '/recommendations/movies/%%API_KEY%%')
  796.     if data == None:
  797.         Debug("Error in request from 'getRecommendedMoviesFromTrakt()'")
  798.     return data
  799.  
  800. def getRecommendedTVShowsFromTrakt():
  801.     data = traktJsonRequest('POST', '/recommendations/shows/%%API_KEY%%')
  802.     if data == None:
  803.         Debug("Error in request from 'getRecommendedTVShowsFromTrakt()'")
  804.     return data
  805.  
  806. def getTrendingMoviesFromTrakt():
  807.     data = traktJsonRequest('GET', '/movies/trending.json/%%API_KEY%%')
  808.     if data == None:
  809.         Debug("Error in request from 'getTrendingMoviesFromTrakt()'")
  810.     return data
  811.  
  812. def getTrendingTVShowsFromTrakt():
  813.     data = traktJsonRequest('GET', '/shows/trending.json/%%API_KEY%%')
  814.     if data == None:
  815.         Debug("Error in request from 'getTrendingTVShowsFromTrakt()'")
  816.     return data
  817.  
  818. def getFriendsFromTrakt():
  819.     data = traktJsonRequest('POST', '/user/friends.json/%%API_KEY%%/%%USERNAME%%')
  820.     if data == None:
  821.         Debug("Error in request from 'getFriendsFromTrakt()'")
  822.     return data
  823.  
  824. def getWatchingFromTraktForUser(name):
  825.     data = traktJsonRequest('POST', '/user/watching.json/%%API_KEY%%/%%USERNAME%%')
  826.     if data == None:
  827.         Debug("Error in request from 'getWatchingFromTraktForUser()'")
  828.     return data
  829.  
  830. def playMovieById(idMovie):
  831.     # httpapi till jsonrpc supports selecting a single movie
  832.     Debug("Play Movie requested for id: "+str(idMovie))
  833.     if idMovie == -1:
  834.         return # invalid movie id
  835.     else:
  836.         rpccmd = json.dumps({'jsonrpc': '2.0', 'method': 'Player.Open', 'params': {'item': {'movieid': int(idMovie)}}, 'id': 1})
  837.         result = xbmc.executeJSONRPC(rpccmd)
  838.         result = json.loads(result)
  839.        
  840.         # check for error
  841.         try:
  842.             error = result['error']
  843.             Debug("playMovieById, Player.Open: " + str(error))
  844.             return None
  845.         except KeyError:
  846.             pass # no error
  847.            
  848.         try:
  849.             if result['result'] == "OK":
  850.                 if xbmc.Player().isPlayingVideo():
  851.                     return True
  852.             notification("Trakt Utilities", __language__(1302).encode( "utf-8", "ignore" )) # Unable to play movie
  853.         except KeyError:
  854.             Debug("playMovieById, VideoPlaylist.Play: KeyError")
  855.             return None
  856.  
  857. ###############################
  858. ##### Scrobbling to trakt #####
  859. ###############################
  860.  
  861. #tell trakt that the user is watching a movie
  862. def watchingMovieOnTrakt(imdb_id, title, year, duration, percent):
  863.     responce = traktJsonRequest('POST', '/movie/watching/%%API_KEY%%', {'imdb_id': imdb_id, 'title': title, 'year': year, 'duration': duration, 'progress': percent}, passVersions=True)
  864.     if responce == None:
  865.         Debug("Error in request from 'watchingMovieOnTrakt()'")
  866.     return responce
  867.  
  868. #tell trakt that the user is watching an episode
  869. def watchingEpisodeOnTrakt(tvdb_id, title, year, season, episode, duration, percent):
  870.     responce = traktJsonRequest('POST', '/show/watching/%%API_KEY%%', {'tvdb_id': tvdb_id, 'title': title, 'year': year, 'season': season, 'episode': episode, 'duration': duration, 'progress': percent}, passVersions=True)
  871.     if responce == None:
  872.         Debug("Error in request from 'watchingEpisodeOnTrakt()'")
  873.     return responce
  874.  
  875. #tell trakt that the user has stopped watching a movie
  876. def cancelWatchingMovieOnTrakt():
  877.     responce = traktJsonRequest('POST', '/movie/cancelwatching/%%API_KEY%%')
  878.     if responce == None:
  879.         Debug("Error in request from 'cancelWatchingMovieOnTrakt()'")
  880.     return responce
  881.  
  882. #tell trakt that the user has stopped an episode
  883. def cancelWatchingEpisodeOnTrakt():
  884.     responce = traktJsonRequest('POST', '/show/cancelwatching/%%API_KEY%%')
  885.     if responce == None:
  886.         Debug("Error in request from 'cancelWatchingEpisodeOnTrakt()'")
  887.     return responce
  888.  
  889. #tell trakt that the user has finished watching an movie
  890. def scrobbleMovieOnTrakt(imdb_id, title, year, duration, percent):
  891.     responce = traktJsonRequest('POST', '/movie/scrobble/%%API_KEY%%', {'imdb_id': imdb_id, 'title': title, 'year': year, 'duration': duration, 'progress': percent}, passVersions=True)
  892.     if responce == None:
  893.         Debug("Error in request from 'scrobbleMovieOnTrakt()'")
  894.     return responce
  895.  
  896. #tell trakt that the user has finished watching an episode
  897. def scrobbleEpisodeOnTrakt(tvdb_id, title, year, season, episode, duration, percent):
  898.     responce = traktJsonRequest('POST', '/show/scrobble/%%API_KEY%%', {'tvdb_id': tvdb_id, 'title': title, 'year': year, 'season': season, 'episode': episode, 'duration': duration, 'progress': percent}, passVersions=True)
  899.     if responce == None:
  900.         Debug("Error in request from 'scrobbleEpisodeOnTrakt()'")
  901.     return responce
  902.  
  903.            
  904.            
  905. """
  906. ToDo:
  907.  
  908.  
  909. """
  910.  
  911.  
  912. """
  913. for later:
  914. First call "Player.GetActivePlayers" to determine the currently active player (audio, video or picture).
  915. If it is audio or video call Audio/VideoPlaylist.GetItems and read the "current" field to get the position of the
  916. currently playling item in the playlist. The "items" field contains an array of all items in the playlist and "items[current]" is
  917. the currently playing file. You can also tell jsonrpc which fields to return for every item in the playlist and therefore you'll have all the information you need.
  918.  
  919. """
  920.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement