The branch, frodo has been updated
via 6e500fe08e9370cf75d3f2e3a564e443809b09f8 (commit)
from 7ad4e2a109ae06fdefb8ba39f531b3c18671830f (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=6e500fe08e9370cf75d3f2e3a564e443809b09f8
commit 6e500fe08e9370cf75d3f2e3a564e443809b09f8
Author: Martijn Kaijser <[email protected]>
Date: Wed Sep 11 09:58:54 2013 +0200
[script.trakt] 2.3.1
diff --git a/script.trakt/addon.xml b/script.trakt/addon.xml
index d7aa5e4..853aedf 100644
--- a/script.trakt/addon.xml
+++ b/script.trakt/addon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="script.trakt" name="trakt" version="2.3.0" provider-name="trakt.tv">
+<addon id="script.trakt" name="trakt" version="2.3.1" provider-name="trakt.tv">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.simplejson" version="2.0.10"/>
diff --git a/script.trakt/changelog.txt b/script.trakt/changelog.txt
index f2e037f..eebe516 100644
--- a/script.trakt/changelog.txt
+++ b/script.trakt/changelog.txt
@@ -1,3 +1,8 @@
+version 2.3.1
+ - improved API error handling and debugging
+ - new context menu action via RunScript(script.trakt,action=contextmenu)
+ - silent option for manual sync via
RunScript(script.trakt,action=sync,silent=True)
+
version 2.3.0
- moved debug settings to their own menu (nate1280)
- new togglewatched action for skins/keymaps (nate1280)
diff --git a/script.trakt/resources/language/English/strings.xml
b/script.trakt/resources/language/English/strings.xml
index 94baf2e..18f9fda 100644
--- a/script.trakt/resources/language/English/strings.xml
+++ b/script.trakt/resources/language/English/strings.xml
@@ -7,6 +7,7 @@
<string id="1017">Number of Retries</string>
<string id="1018">Startup Delay</string>
<string id="1019">Force a reload of settings from trakt.tv, save
settings when finished</string>
+ <string id="1020">Default script action</string>
<!-- Rating Settings -->
<string id="1030">Rating</string>
@@ -23,6 +24,8 @@
<string id="1043">Minimum percent watched to scrobble</string>
<string id="1044">During scrobbling, update ID for library movie if ID
is missing</string>
<string id="1045">During scrobbling, update ID for library tv show if
ID is missing</string>
+ <string id="1046">Send watching call on seek</string>
+ <string id="1047">Send watching call on resume</string>
<string id="1050">Exclusions</string>
<string id="1051">Exclude Live TV</string>
<string id="1052">Exclude HTTP sources</string>
@@ -216,4 +219,17 @@
<string id="1704">Simulate tagging</string>
<string id="1720">Logging</string>
<string id="1721">Simulate settings, if enabled will not make changes
in XBMC or trakt.tv</string>
+
+ <!-- Context Menu Entries -->
+ <string id="2000">Manage Movie's Lists</string>
+ <string id="2001">Manage Show's Lists</string>
+ <string id="2010">Remove from Watchlist</string>
+ <string id="2020">Add to Watchlist</string>
+ <string id="2030">Rate this Movie</string>
+ <string id="2031">Rate this Show</string>
+ <string id="2032">Rate this Episode</string>
+ <string id="2040">Toggle Watched</string>
+ <string id="2050">Manage All Lists</string>
+ <string id="2060">Update All Tags</string>
+ <string id="2070">Synchronize Library</string>
</strings>
diff --git a/script.trakt/resources/settings.xml
b/script.trakt/resources/settings.xml
index 5538e42..006a434 100644
--- a/script.trakt/resources/settings.xml
+++ b/script.trakt/resources/settings.xml
@@ -5,6 +5,7 @@
<setting id="password" type="text" option="hidden" label="1014"
default="" />
<setting id="retries" type="slider" label="1017" range="1,1,10"
default="5" option="int"/>
<setting id="startup_delay" type="slider" label="1018"
range="0,30" default="0" option="int"/>
+ <setting id="default_action" type="enum" label="1020"
values="Manual Sync|Manage Lists" default="0" />
<setting type="action" label="1019"
action="RunScript(script.trakt,action=loadsettings)"/>
</category>
<category label="1050"><!-- Exclusions -->
@@ -23,6 +24,8 @@
<setting id="scrobble_min_view_time" type="slider" label="1043"
range="0,5,100" default="80"/>
<setting id="update_imdb_id" type="bool" label="1044"
default="false"/>
<setting id="update_tvdb_id" type="bool" label="1045"
default="false"/>
+ <setting id="watching_call_on_seek" type="bool" label="1046"
default="true"/>
+ <setting id="watching_call_on_resume" type="bool" label="1047"
default="true"/>
</category>
<category label="1400"><!-- Synchronize -->
<setting label="1410" type="lsep"/><!-- Service -->
diff --git a/script.trakt/script.py b/script.trakt/script.py
index a1ec449..afd9b28 100644
--- a/script.trakt/script.py
+++ b/script.trakt/script.py
@@ -6,6 +6,7 @@ import sys
import queue
import tagging
import time
+from traktContextMenu import traktContextMenu
try:
import simplejson as json
@@ -27,9 +28,10 @@ def getMediaType():
def getArguments():
data = None
-
+ default_actions = {0: "sync", 1: "managelists"}
+ default = utils.getSettingAsInt('default_action')
if len(sys.argv) == 1:
- data = {'action': "sync"}
+ data = {'action': default_actions[default]}
else:
data = {}
for item in sys.argv:
@@ -45,8 +47,57 @@ def Main():
args = getArguments()
data = {}
+ if args['action'] == 'contextmenu':
+ buttons = []
+ media_type = getMediaType()
+
+ if utils.getSettingAsBool('tagging_enable'):
+ if utils.isMovie(media_type):
+ buttons.append("itemlists")
+ dbid = int(xbmc.getInfoLabel('ListItem.DBID'))
+ result = utils.getMovieDetailsFromXbmc(dbid,
['tag'])
+ if tagging.hasTraktWatchlistTag(result['tag']):
+ buttons.append("removefromlist")
+ else:
+ buttons.append("addtolist")
+ elif utils.isShow(media_type):
+ buttons.append("itemlists")
+ dbid = int(xbmc.getInfoLabel('ListItem.DBID'))
+ result = utils.getShowDetailsFromXBMC(dbid,
['tag'])
+ if tagging.hasTraktWatchlistTag(result['tag']):
+ buttons.append("removefromlist")
+ else:
+ buttons.append("addtolist")
+
+ if media_type in ['movie', 'show', 'episode']:
+ buttons.append("rate")
+
+ if media_type in ['movie', 'show', 'season', 'episode']:
+ buttons.append("togglewatched")
+
+ if utils.getSettingAsBool('tagging_enable'):
+ buttons.append("managelists")
+ buttons.append("updatetags")
+ buttons.append("sync")
+
+ contextMenu = traktContextMenu(media_type=media_type,
buttons=buttons)
+ contextMenu.doModal()
+ _action = contextMenu.action
+ del contextMenu
+
+ if _action is None:
+ return
+
+ utils.Debug("'%s' selected from trakt.tv action menu" % _action)
+ args['action'] = _action
+ if _action in ['addtolist', 'removefromlist']:
+ args['list'] = "watchlist"
+
if args['action'] == 'sync':
data = {'action': 'manualSync'}
+ data['silent'] = False
+ if 'silent' in args:
+ data['silent'] = (args['silent'].lower() == 'true')
elif args['action'] == 'loadsettings':
data = {'action': 'loadsettings', 'force': True}
diff --git a/script.trakt/scrobbler.py b/script.trakt/scrobbler.py
index 7206a88..823d9b3 100755
--- a/script.trakt/scrobbler.py
+++ b/script.trakt/scrobbler.py
@@ -117,6 +117,7 @@ class Scrobbler():
self.curVideoInfo =
utilities.getMovieDetailsFromXbmc(self.curVideo['id'], ['imdbnumber', 'title',
'year'])
if
utilities.getSettingAsBool('rate_movie'):
# pre-get sumamry information,
for faster rating dialog.
+ Debug("[Scrobbler] Movie rating
is enabled, pre-fetching summary information.")
imdb_id =
self.curVideoInfo['imdbnumber']
if imdb_id.startswith("tt") or
imdb_id.isdigit():
self.traktSummaryInfo =
self.traktapi.getMovieSummary(self.curVideoInfo['imdbnumber'])
@@ -135,6 +136,7 @@ class Scrobbler():
self.curVideoInfo =
utilities.getEpisodeDetailsFromXbmc(self.curVideo['id'], ['showtitle',
'season', 'episode', 'tvshowid', 'uniqueid'])
if
utilities.getSettingAsBool('rate_episode'):
# pre-get sumamry information,
for faster rating dialog.
+ Debug("[Scrobbler] Episode
rating is enabled, pre-fetching summary information.")
tvdb_id =
self.curVideoInfo['tvdb_id']
if tvdb_id.isdigit() or
tvdb_id.startswith("tt"):
self.traktSummaryInfo =
self.traktapi.getEpisodeSummary(tvdb_id, self.curVideoInfo['season'],
self.curVideoInfo['episode'])
@@ -173,7 +175,8 @@ class Scrobbler():
self.pausedAt = 0
self.isPaused = False
self.update(True)
- self.watching()
+ if
utilities.getSettingAsBool('watching_call_on_resume'):
+ self.watching()
def playbackPaused(self):
if not self.isPlaying:
@@ -191,7 +194,8 @@ class Scrobbler():
Debug("[Scrobbler] playbackSeek()")
self.update(True)
- self.watching()
+ if utilities.getSettingAsBool('watching_call_on_seek'):
+ self.watching()
def playbackEnded(self):
if not self.isPlaying:
@@ -239,9 +243,10 @@ class Scrobbler():
self.curVideoInfo['imdbnumber'] = response['movie']['imdb_id']
if 'id' in
self.curVideo and utilities.getSettingAsBool('update_imdb_id'):
req =
{"jsonrpc": "2.0", "id": 1, "method": "VideoLibrary.SetMovieDetails", "params":
{"movieid" : self.curVideoInfo['movieid'], "imdbnumber":
self.curVideoInfo['imdbnumber']}}
-
utils.xbmcJsonRequest(req)
+
utilities.xbmcJsonRequest(req)
# get summary data now
if we are rating this movie
if
utilities.getSettingAsBool('rate_movie') and self.traktSummaryInfo is None:
+
Debug("[Scrobbler] Movie rating is enabled, pre-fetching summary information.")
self.traktSummaryInfo =
self.traktapi.getMovieSummary(self.curVideoInfo['imdbnumber'])
Debug("[Scrobbler] Watch response: %s" %
str(response))
@@ -262,9 +267,10 @@ class Scrobbler():
self.curVideoInfo['tvdb_id'] = response['show']['tvdb_id']
if 'id' in
self.curVideo and utilities.getSettingAsBool('update_tvdb_id'):
req =
{"jsonrpc": "2.0", "id": 1, "method": "VideoLibrary.SetTVShowDetails",
"params": {"tvshowid" : self.curVideoInfo['tvshowid'], "imdbnumber":
self.curVideoInfo['tvdb_id']}}
-
utils.xbmcJsonRequest(req)
+
utilities.xbmcJsonRequest(req)
# get summary data now
if we are rating this episode
if
utilities.getSettingAsBool('rate_episode') and self.traktSummaryInfo is None:
+
Debug("[Scrobbler] Episode rating is enabled, pre-fetching summary
information.")
self.traktSummaryInfo =
self.traktapi.getEpisodeSummary(self.curVideoInfo['tvdb_id'],
self.curVideoInfo['season'], self.curVideoInfo['episode'])
Debug("[Scrobbler] Watch response: %s" %
str(response))
@@ -304,6 +310,8 @@ class Scrobbler():
if
response['error'].startswith("scrobbled") and
response['error'].endswith("already"):
Debug("[Scrobbler] Movie was
just recently scrobbled, attempting to cancel watching instead.")
self.stoppedWatching()
+ elif response['error'] == "movie not
found":
+ Debug("[Scrobbler] Movie '%s'
was not found on trakt.tv, possible malformed XBMC metadata." %
self.curVideoInfo['title'])
elif utilities.isEpisode(self.curVideo['type']) and
scrobbleEpisodeOption:
if self.isMultiPartEpisode:
@@ -320,6 +328,8 @@ class Scrobbler():
if
response['error'].startswith("scrobbled") and
response['error'].endswith("already"):
Debug("[Scrobbler] Episode was
just recently scrobbled, attempting to cancel watching instead.")
self.stoppedWatching()
+ elif response['error'] == "show not
found":
+ Debug("[Scrobbler] Show '%s'
was not found on trakt.tv, possible malformed XBMC metadata." %
self.curVideoInfo['showtitle'])
def watchlistTagCheck(self):
if not utilities.isMovie(self.curVideo['type']):
@@ -343,7 +353,7 @@ class Scrobbler():
tagging.xbmcSetTags(id, self.curVideo['type'],
s, tags)
else:
- utils.Debug("No data was returned from XBMC, aborting
tag udpate.")
+ utilities.Debug("No data was returned from XBMC,
aborting tag udpate.")
def check(self):
scrobbleMinViewTimeOption =
utilities.getSettingAsFloat("scrobble_min_view_time")
diff --git a/script.trakt/service.py b/script.trakt/service.py
index 410a109..1144585 100644
--- a/script.trakt/service.py
+++ b/script.trakt/service.py
@@ -72,7 +72,7 @@ class traktService:
elif action == 'manualSync':
if not self.syncThread.isAlive():
utilities.Debug("Performing a manual sync.")
- self.doSync(manual=True)
+ self.doSync(manual=True, silent=data['silent'])
else:
utilities.Debug("There already is a sync in
progress.")
elif action == 'updatetags':
@@ -345,21 +345,22 @@ class traktService:
if markedNotification:
utilities.notification(utilities.getString(1550), utilities.getString(1552) %
(len(params['episodes']), s))
- def doSync(self, manual=False):
- self.syncThread = syncThread(manual)
+ def doSync(self, manual=False, silent=False):
+ self.syncThread = syncThread(manual, silent)
self.syncThread.start()
class syncThread(threading.Thread):
_isManual = False
- def __init__(self, isManual=False):
+ def __init__(self, isManual=False, runSilent=False):
threading.Thread.__init__(self)
self.name = "trakt-sync"
self._isManual = isManual
+ self._runSilent = runSilent
def run(self):
- sync = Sync(show_progress=self._isManual, api=globals.traktapi)
+ sync = Sync(show_progress=self._isManual,
run_silent=self._runSilent, api=globals.traktapi)
sync.sync()
if utilities.getSettingAsBool('tagging_enable') and
utilities.getSettingAsBool('tagging_tag_after_sync'):
diff --git a/script.trakt/sync.py b/script.trakt/sync.py
index 428deb5..97eeccd 100644
--- a/script.trakt/sync.py
+++ b/script.trakt/sync.py
@@ -10,9 +10,12 @@ progress = xbmcgui.DialogProgress()
class Sync():
- def __init__(self, show_progress=False, api=None):
+ def __init__(self, show_progress=False, run_silent=False, api=None):
self.traktapi = api
self.show_progress = show_progress
+ self.run_silent = run_silent
+ if self.show_progress and self.run_silent:
+ Debug("[Sync] Sync is being run silently.")
self.notify =
utilities.getSettingAsBool('show_sync_notifications')
self.simulate = utilities.getSettingAsBool('simulate_sync')
if self.simulate:
@@ -28,7 +31,7 @@ class Sync():
self.exclusions.append(_path)
def isCanceled(self):
- if self.show_progress and progress.iscanceled():
+ if self.show_progress and not self.run_silent and
progress.iscanceled():
Debug("[Sync] Sync was canceled by user.")
return True
elif xbmc.abortRequested:
@@ -38,7 +41,7 @@ class Sync():
return False
def updateProgress(self, *args, **kwargs):
- if self.show_progress:
+ if self.show_progress and not self.run_silent:
kwargs['percent'] = args[0]
progress.update(**kwargs)
@@ -417,17 +420,21 @@ class Sync():
def syncEpisodes(self):
if not self.show_progress and
utilities.getSettingAsBool('sync_on_update') and self.notify:
notification('%s %s' % (utilities.getString(1400),
utilities.getString(1406)), utilities.getString(1420)) #Sync started
- if self.show_progress:
+ if self.show_progress and not self.run_silent:
progress.create("%s %s" % (utilities.getString(1400),
utilities.getString(1406)), line1=" ", line2=" ", line3=" ")
xbmcShows = self.xbmcLoadShows()
if not isinstance(xbmcShows, list) and not xbmcShows:
Debug("[Episodes Sync] XBMC show list is empty,
aborting tv show Sync.")
+ if self.show_progress and not self.run_silent:
+ progress.close()
return
traktShows = self.traktLoadShows()
if not isinstance(traktShows, list):
Debug("[Episodes Sync] Error getting trakt.tv show
list, aborting tv show sync.")
+ if self.show_progress and not self.run_silent:
+ progress.close()
return
if utilities.getSettingAsBool('add_episodes_to_trakt') and not
self.isCanceled():
@@ -443,13 +450,13 @@ class Sync():
self.xbmcUpdateEpisodes(xbmcShowsUpadate)
if utilities.getSettingAsBool('clean_trakt_episodes') and not
self.isCanceled():
- raktShowsRemove = self.compareShows(traktShows,
xbmcShows)
- self.traktRemoveEpisodes(raktShowsRemove)
+ traktShowsRemove = self.compareShows(traktShows,
xbmcShows)
+ self.traktRemoveEpisodes(traktShowsRemove)
if not self.show_progress and
utilities.getSettingAsBool('sync_on_update') and self.notify:
notification('%s %s' % (utilities.getString(1400),
utilities.getString(1406)), utilities.getString(1421)) #Sync complete
- if not self.isCanceled() and self.show_progress:
+ if not self.isCanceled() and self.show_progress and not
self.run_silent:
self.updateProgress(100, line1=" ",
line2=utilities.getString(1442), line3=" ")
progress.close()
@@ -554,6 +561,7 @@ class Sync():
del(movie['imdbnumber'])
del(movie['lastplayed'])
del(movie['label'])
+ del(movie['file'])
xbmc_movies.append(movie)
@@ -699,17 +707,21 @@ class Sync():
def syncMovies(self):
if not self.show_progress and
utilities.getSettingAsBool('sync_on_update') and self.notify:
notification('%s %s' % (utilities.getString(1400),
utilities.getString(1402)), utilities.getString(1420)) #Sync started
- if self.show_progress:
+ if self.show_progress and not self.run_silent:
progress.create("%s %s" % (utilities.getString(1400),
utilities.getString(1402)), line1=" ", line2=" ", line3=" ")
xbmcMovies = self.xbmcLoadMovies()
if not isinstance(xbmcMovies, list) and not xbmcMovies:
Debug("[Movies Sync] XBMC movie list is empty, aborting
movie Sync.")
+ if self.show_progress and not self.run_silent:
+ progress.close()
return
traktMovies = self.traktLoadMovies()
if not isinstance(traktMovies, list):
Debug("[Movies Sync] Error getting trakt.tv movie list,
aborting movie Sync.")
+ if self.show_progress and not self.run_silent:
+ progress.close()
return
if utilities.getSettingAsBool('add_movies_to_trakt') and not
self.isCanceled():
@@ -728,7 +740,7 @@ class Sync():
traktMoviesToRemove = self.compareMovies(traktMovies,
xbmcMovies)
self.traktRemoveMovies(traktMoviesToRemove)
- if not self.isCanceled() and self.show_progress:
+ if not self.isCanceled() and self.show_progress and not
self.run_silent:
self.updateProgress(100,
line1=utilities.getString(1431), line2=" ", line3=" ")
progress.close()
diff --git a/script.trakt/traktapi.py b/script.trakt/traktapi.py
index 40079e2..f9a514d 100644
--- a/script.trakt/traktapi.py
+++ b/script.trakt/traktapi.py
@@ -38,6 +38,7 @@ class traktError(Exception):
class traktAuthProblem(traktError): pass
class traktServerBusy(traktError): pass
class traktUnknownError(traktError): pass
+class traktNotFoundError(traktError): pass
class traktNetworkError(traktError):
def __init__(self, value, timeout):
super(traktNetworkError, self).__init__(value)
@@ -94,7 +95,12 @@ class traktAPI(object):
elif e.code == 503: # server busy problem
raise traktServerBusy(error_data)
else:
- raise traktUnknownError(error_data,
e.code)
+ try:
+ _data = json.loads(error_data)
+ if 'status' in _data:
+ data = error_data
+ except ValueError:
+ raise
traktUnknownError(error_data, e.code)
elif hasattr(e, 'reason'): # usually a read timeout, or
unable to reach host
raise traktNetworkError(str(e.reason),
isinstance(e.reason, socket.timeout))
@@ -161,6 +167,7 @@ class traktAPI(object):
except traktError, e:
if isinstance(e, traktServerBusy):
Debug("[traktAPI] traktRequest(): (%i)
Server Busy (%s)" % (i, e.value))
+ xbmc.sleep(5000)
elif isinstance(e, traktAuthProblem):
Debug("[traktAPI] traktRequest(): (%i)
Authentication Failure (%s)" % (i, e.value))
setSetting('account_valid', False)
@@ -199,12 +206,12 @@ class traktAPI(object):
Debug("[traktAPI] traktRequest(): (%i)
JSON response: '%s'" % (i, str(data)))
except ValueError:
# malformed json response
- Debug("[traktAPI] traktRequest(): (%i) Bad JSON
response: '%s'", (i, raw))
+ Debug("[traktAPI] traktRequest(): (%i) Bad JSON
response: '%s'" % (i, raw))
if not silent:
notification('trakt', getString(1109) +
": Bad response from trakt") # Error
# check for the status variable in JSON data
- if 'status' in data:
+ if data and 'status' in data:
if data['status'] == 'success':
break
elif returnOnFailure and data['status'] ==
'failure':
diff --git a/script.trakt/utilities.py b/script.trakt/utilities.py
index e6e2806..ec67d4e 100755
--- a/script.trakt/utilities.py
+++ b/script.trakt/utilities.py
@@ -16,6 +16,9 @@ except ImportError:
# read settings
__addon__ = xbmcaddon.Addon('script.trakt')
+# make strptime call prior to doing anything, to try and prevent threading
errors
+time.strptime("1970-01-01 12:00:00", "%Y-%m-%d %H:%M:%S")
+
def Debug(msg, force = False):
if(getSettingAsBool('debug') or force):
try:
-----------------------------------------------------------------------
Summary of changes:
script.trakt/.gitignore | 4 +
script.trakt/addon.xml | 2 +-
script.trakt/changelog.txt | 5 +
.../resources/language/English/strings.xml | 16 ++++
script.trakt/resources/settings.xml | 3 +
.../skins/Default/720p/traktContextMenu.xml | 85 ++++++++++++++++++++
script.trakt/script.py | 55 ++++++++++++-
script.trakt/scrobbler.py | 20 ++++-
script.trakt/service.py | 11 ++-
script.trakt/sync.py | 30 +++++--
script.trakt/traktContextMenu.py | 82 +++++++++++++++++++
script.trakt/traktapi.py | 13 +++-
script.trakt/utilities.py | 3 +
13 files changed, 304 insertions(+), 25 deletions(-)
create mode 100644 script.trakt/.gitignore
create mode 100644
script.trakt/resources/skins/Default/720p/traktContextMenu.xml
create mode 100644 script.trakt/traktContextMenu.py
hooks/post-receive
--
Scripts
------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. Consolidate legacy IT systems to a single system of record for IT
2. Standardize and globalize service processes across IT
3. Implement zero-touch automation to replace manual, redundant tasks
http://pubads.g.doubleclick.net/gampad/clk?id=51271111&iu=/4140/ostg.clktrk
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons