class traktService: scrobbler = None tagger = None updateTagsThread = None watcher = None syncThread = None dispatchQueue = queue.SqliteQueue() _interval = 10 * 60 # how often to send watching call def __init__(self): threading.Thread.name = 'trakt' def _dispatchQueue(self, data): utilities.Debug("Queuing for dispatch: %s" % data) self.dispatchQueue.append(data) def _dispatch(self, data): utilities.Debug("Dispatch: %s" % data) action = data['action'] if action == 'started': del data['action'] self.scrobbler.playbackStarted(data) self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() elif action == 'ended' or action == 'stopped': self.scrobbler.playbackEnded() if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() self.watcher = None elif action == 'paused': self.scrobbler.playbackPaused() elif action == 'resumed': self.scrobbler.playbackResumed() elif action == 'seek' or action == 'seekchapter': self.scrobbler.playbackSeek() elif action == 'databaseUpdated': self.doSync() elif action == 'scanStarted': pass elif action == 'settingsChanged': utilities.Debug("Settings changed, reloading.") globals.traktapi.updateSettings() self.tagger.updateSettings() elif action == 'markWatched': del data['action'] self.doMarkWatched(data) elif action == 'manualRating': ratingData = data['ratingData'] self.doManualRating(ratingData) elif action == 'manualSync': if not self.syncThread.isAlive(): utilities.Debug("Performing a manual sync.") self.doSync(manual=True, silent=data['silent']) else: utilities.Debug("There already is a sync in progress.") elif action == 'updatetags': if self.updateTagsThread and self.updateTagsThread.isAlive(): utilities.Debug("Currently updating tags already.") else: self.updateTagsThread = threading.Thread(target=self.tagger.updateTagsFromTrakt, name="trakt-updatetags") self.updateTagsThread.start() elif action == 'managelists': self.tagger.manageLists() elif action == 'itemlists': del data['action'] self.tagger.itemLists(data) elif action == 'addtolist': del data['action'] list = data['list'] del data['list'] self.tagger.manualAddToList(list, data) elif action == 'removefromlist': del data['action'] list = data['list'] del data['list'] self.tagger.manualRemoveFromList(list, data) elif action == 'loadsettings': force = False if 'force' in data: force = data['force'] globals.traktapi.getAccountSettings(force) else: utilities.Debug("Unknown dispatch action, '%s'." % action) def run(self): startup_delay = utilities.getSettingAsInt('startup_delay') if startup_delay: utilities.Debug("Delaying startup by %d seconds." % startup_delay) xbmc.sleep(startup_delay * 1000) utilities.Debug("Service thread starting.") # purge queue before doing anything self.dispatchQueue.purge() # queue a loadsettings action self.dispatchQueue.append({'action': 'loadsettings'}) # setup event driven classes self.Player = traktPlayer(action = self._dispatchQueue) self.Monitor = traktMonitor(action = self._dispatchQueue) # init traktapi class globals.traktapi = traktAPI() # init sync thread self.syncThread = syncThread() # init scrobbler class self.scrobbler = Scrobbler(globals.traktapi) # init tagging class self.tagger = Tagger(globals.traktapi) # start loop for events while (not xbmc.abortRequested): while len(self.dispatchQueue) and (not xbmc.abortRequested): data = self.dispatchQueue.get() utilities.Debug("Queued dispatch: %s" % data) self._dispatch(data) if xbmc.Player().isPlayingVideo(): self.scrobbler.update() xbmc.sleep(500) # we are shutting down utilities.Debug("Beginning shut down.") # check if watcher is set and active, if so, cancel it. if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() # delete player/monitor del self.Player del self.Monitor # check update tags thread. if self.updateTagsThread and self.updateTagsThread.isAlive(): self.updateTagsThread.join() # check if sync thread is running, if so, join it. if self.syncThread.isAlive(): self.syncThread.join() def doWatching(self): # check if we're still playing a video if not xbmc.Player().isPlayingVideo(): self.watcher = None return # call watching method self.scrobbler.watching() # start a new timer thread self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() def doManualRating(self, data): action = data['action'] media_type = data['media_type'] summaryInfo = None if not utilities.isValidMediaType(media_type): utilities.Debug("doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action)) return if not data['action'] in ['rate', 'unrate']: utilities.Debug("doManualRating(): Unknown action passed.") return if 'dbid' in data: utilities.Debug("Getting data for manual %s of library '%s' with ID of '%s'" % (action, media_type, data['dbid'])) elif 'remoteitd' in data: if 'season' in data: utilities.Debug("Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'." % (action, media_type, data['season'], data['episode'], data['remoteid'])) else: utilities.Debug("Getting data for manual %s of non-library '%s' with ID of '%s'" % (action, media_type, data['remoteid'])) if utilities.isEpisode(media_type): summaryInfo = globals.traktapi.getEpisodeSummary(data['tvdb_id'], data['season'], data['episode']) elif utilities.isShow(media_type): summaryInfo = globals.traktapi.getShowSummary(data['imdbnumber']) elif utilities.isMovie(media_type): summaryInfo = globals.traktapi.getMovieSummary(data['imdbnumber']) if not summaryInfo is None: if utilities.isMovie(media_type) or utilities.isShow(media_type): summaryInfo['xbmc_id'] = data['dbid'] if action == 'rate': if not 'rating' in data: rateMedia(media_type, summaryInfo) else: rateMedia(media_type, summaryInfo, rating=data['rating']) elif action == 'unrate': rateMedia(media_type, summaryInfo, unrate=True) else: utilities.Debug("doManualRating(): Summary info was empty, possible problem retrieving data from trakt.tv") def doMarkWatched(self, data): media_type = data['media_type'] simulate = utilities.getSettingAsBool('simulate_sync') markedNotification = utilities.getSettingAsBool('show_marked_notification') if utilities.isMovie(media_type): summaryInfo = globals.traktapi.getMovieSummary(data['id']) if summaryInfo: if not summaryInfo['watched']: s = utilities.getFormattedItemName(media_type, summaryInfo) utilities.Debug("doMarkWatched(): '%s' is not watched on trakt, marking it as watched." % s) movie = {} movie['imdb_id'] = data['id'] movie['title'] = summaryInfo['title'] movie['year'] = summaryInfo['year'] movie['plays'] = 1 movie['last_played'] = int(time()) params = {'movies': [movie]} utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenMovie(params) if result: if markedNotification: utilities.notification(utilities.getString(1550), s) else: utilities.notification(utilities.getString(1551), s) else: if markedNotification: utilities.notification(utilities.getString(1550), s) elif utilities.isEpisode(media_type): summaryInfo = globals.traktapi.getEpisodeSummary(data['id'], data['season'], data['episode']) if summaryInfo: if not summaryInfo['episode']['watched']: s = utilities.getFormattedItemName(media_type, summaryInfo) utilities.Debug("doMarkWathced(): '%s' is not watched on trakt, marking it as watched." % s) params = {} params['imdb_id'] = summaryInfo['show']['imdb_id'] params['tvdb_id'] = summaryInfo['show']['tvdb_id'] params['title'] = summaryInfo['show']['title'] params['year'] = summaryInfo['show']['year'] params['episodes'] = [{'season': data['season'], 'episode': data['episode']}] utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification(utilities.getString(1550), s) else: utilities.notification(utilities.getString(1551), s) else: if markedNotification: utilities.notification(utilities.getString(1550), s) elif utilities.isSeason(media_type): showInfo = globals.traktapi.getShowSummary(data['id']) if not showInfo: return summaryInfo = globals.traktapi.getSeasonInfo(data['id'], data['season']) if summaryInfo: showInfo['season'] = data['season'] s = utilities.getFormattedItemName(media_type, showInfo) params = {} params['imdb_id'] = showInfo['imdb_id'] params['tvdb_id'] = showInfo['tvdb_id'] params['title'] = showInfo['title'] params['year'] = showInfo['year'] params['episodes'] = [] for ep in summaryInfo: if ep['episode'] in data['episodes']: if not ep['watched']: params['episodes'].append({'season': ep['season'], 'episode': ep['episode']}) utilities.Debug("doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched." % (showInfo['title'], data['season'], len(params['episodes']))) if len(params['episodes']) > 0: utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) else: utilities.notification(utilities.getString(1551), utilities.getString(1552) % (len(params['episodes']), s)) else: if markedNotification: utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) elif utilities.isShow(media_type): summaryInfo = globals.traktapi.getShowSummary(data['id'], extended=True) if summaryInfo: s = utilities.getFormattedItemName(media_type, summaryInfo) params = {} params['imdb_id'] = summaryInfo['imdb_id'] params['tvdb_id'] = summaryInfo['tvdb_id'] params['title'] = summaryInfo['title'] params['year'] = summaryInfo['year'] params['episodes'] = [] for season in summaryInfo['seasons']: for ep in season['episodes']: if str(season['season']) in data['seasons']: if ep['episode'] in data['seasons'][str(season['season'])]: if not ep['watched']: params['episodes'].append({'season': ep['season'], 'episode': ep['episode']}) utilities.Debug("doMarkWatched(): '%s' has %d episode(s) that are going to be marked as watched." % (summaryInfo['title'], len(params['episodes']))) if len(params['episodes']) > 0: utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) else: utilities.notification(utilities.getString(1551), utilities.getString(1552) % (len(params['episodes']), s)) else: if markedNotification: utilities.notification(utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) def doSync(self, manual=False, silent=False): self.syncThread = syncThread(manual, silent) self.syncThread.start()
class traktService: scrobbler = None watcher = None syncThread = None dispatchQueue = Queue.Queue() _interval = 10 * 60 # how often to send watching call def __init__(self): threading.Thread.name = 'trakt' def _dispatchQueue(self, data): utilities.Debug("Queuing for dispatch: %s" % data) self.dispatchQueue.put(data) def _dispatch(self, data): utilities.Debug("Dispatch: %s" % data) action = data['action'] if action == 'started': del data['action'] self.scrobbler.playbackStarted(data) self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() elif action == 'ended' or action == 'stopped': self.scrobbler.playbackEnded() if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() self.watcher = None elif action == 'paused': self.scrobbler.playbackPaused() elif action == 'resumed': self.scrobbler.playbackResumed() elif action == 'seek' or action == 'seekchapter': self.scrobbler.playbackSeek() elif action == 'databaseUpdated': self.doSync() elif action == 'scanStarted': pass elif action == 'settingsChanged': utilities.Debug("Settings changed, reloading.") globals.traktapi.updateSettings() else: utilities.Debug("Unknown dispatch action, '%s'." % action) def run(self): startup_delay = utilities.getSettingAsInt('startup_delay') if startup_delay: utilities.Debug("Delaying startup by %d seconds." % startup_delay) xbmc.sleep(startup_delay * 1000) utilities.Debug("Service thread starting.") # clear any left over properties utilities.clearProperty('traktManualSync') utilities.clearProperty('traktManualRateData') utilities.clearProperty('traktManualRate') # setup event driven classes self.Player = traktPlayer(action = self._dispatchQueue) self.Monitor = traktMonitor(action = self._dispatchQueue) # init traktapi class globals.traktapi = traktAPI() # init sync thread self.syncThread = syncThread() # init scrobbler class self.scrobbler = Scrobbler(globals.traktapi) # start loop for events while (not xbmc.abortRequested): while not self.dispatchQueue.empty() and (not xbmc.abortRequested): data = self.dispatchQueue.get() utilities.Debug("Queued dispatch: %s" % data) self._dispatch(data) # check if we were tasked to do a manual sync if utilities.getPropertyAsBool('traktManualSync'): if not self.syncThread.isAlive(): utilities.Debug("Performing a manual sync.") self.doSync(manual=True) else: utilities.Debug("There already is a sync in progress.") utilities.clearProperty('traktManualSync') # check if we were tasked to do a manual rating if utilities.getPropertyAsBool('traktManualRate'): self.doManualRating() utilities.clearProperty('traktManualRateData') utilities.clearProperty('traktManualRate') if xbmc.Player().isPlayingVideo(): self.scrobbler.update() xbmc.sleep(500) # we are shutting down utilities.Debug("Beginning shut down.") # check if watcher is set and active, if so, cancel it. if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() # delete player/monitor del self.Player del self.Monitor # check if sync thread is running, if so, join it. if self.syncThread.isAlive(): self.syncThread.join() def doWatching(self): # check if we're still playing a video if not xbmc.Player().isPlayingVideo(): self.watcher = None return # call watching method self.scrobbler.watching() # start a new timer thread self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() def doManualRating(self): data = json.loads(utilities.getProperty('traktManualRateData')) action = data['action'] media_type = data['media_type'] summaryInfo = None if not utilities.isValidMediaType(media_type): utilities.Debug("doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action)) return if not data['action'] in ['rate', 'unrate']: utilities.Debug("doManualRating(): Unknown action passed.") return if 'dbid' in data: utilities.Debug("Getting data for manual %s of library '%s' with ID of '%s'" % (action, media_type, data['dbid'])) elif 'remoteitd' in data: if 'season' in data: utilities.Debug("Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'." % (action, media_type, data['season'], data['episode'], data['remoteid'])) else: utilities.Debug("Getting data for manual %s of non-library '%s' with ID of '%s'" % (action, media_type, data['remoteid'])) if utilities.isEpisode(media_type): result = {} if 'dbid' in data: result = utilities.getEpisodeDetailsFromXbmc(data['dbid'], ['showtitle', 'season', 'episode', 'tvshowid']) if not result: utilities.Debug("doManualRating(): No data was returned from XBMC, aborting manual %s." % action) return else: result['tvdb_id'] = data['remoteid'] result['season'] = data['season'] result['episode'] = data['episode'] summaryInfo = globals.traktapi.getEpisodeSummary(result['tvdb_id'], result['season'], result['episode']) elif utilities.isShow(media_type): result = {} if 'dbid' in data: result = utilities.getShowDetailsFromXBMC(data['dbid'], ['imdbnumber']) if not result: utilities.Debug("doManualRating(): No data was returned from XBMC, aborting manual %s." % action) return else: result['imdbnumber'] = data['remoteid'] summaryInfo = globals.traktapi.getShowSummary(result['imdbnumber']) elif utilities.isMovie(media_type): result = {} if 'dbid' in data: result = utilities.getMovieDetailsFromXbmc(data['dbid'], ['imdbnumber', 'title', 'year']) if not result: utilities.Debug("doManualRating(): No data was returned from XBMC, aborting manual %s." % action) return else: result['imdbnumber'] = data['remoteid'] summaryInfo = globals.traktapi.getMovieSummary(result['imdbnumber']) if not summaryInfo is None: if action == 'rate': if not 'rating' in data: rateMedia(media_type, summaryInfo) else: rateMedia(media_type, summaryInfo, rating=data['rating']) elif action == 'unrate': rateMedia(media_type, summaryInfo, unrate=True) else: utilities.Debug("doManualRating(): Summary info was empty, possible problem retrieving data from trakt.tv") def doSync(self, manual=False): self.syncThread = syncThread(manual) self.syncThread.start()
class traktService: scrobbler = None updateTagsThread = None syncThread = None dispatchQueue = sqlitequeue.SqliteQueue() def __init__(self): threading.Thread.name = 'trakt' def _dispatchQueue(self, data): logger.debug("Queuing for dispatch: %s" % data) self.dispatchQueue.append(data) def _dispatch(self, data): try: logger.debug("Dispatch: %s" % data) action = data['action'] if action == 'started': del data['action'] self.scrobbler.playbackStarted(data) elif action == 'ended' or action == 'stopped': self.scrobbler.playbackEnded() elif action == 'paused': self.scrobbler.playbackPaused() elif action == 'resumed': self.scrobbler.playbackResumed() elif action == 'seek' or action == 'seekchapter': self.scrobbler.playbackSeek() elif action == 'databaseUpdated': if utilities.getSettingAsBool('sync_on_update'): logger.debug("Performing sync after library update.") self.doSync() elif action == 'databaseCleaned': if utilities.getSettingAsBool('sync_on_update') and ( utilities.getSettingAsBool('clean_trakt_movies') or utilities.getSettingAsBool('clean_trakt_episodes')): logger.debug("Performing sync after library clean.") self.doSync() elif action == 'settingsChanged': logger.debug("Settings changed, reloading.") globals.traktapi.updateSettings() elif action == 'markWatched': del data['action'] self.doMarkWatched(data) elif action == 'manualRating': ratingData = data['ratingData'] self.doManualRating(ratingData) elif action == 'manualSync': if not self.syncThread.isAlive(): logger.debug("Performing a manual sync.") self.doSync(manual=True, silent=data['silent'], library=data['library']) else: logger.debug("There already is a sync in progress.") elif action == 'settings': utilities.showSettings() elif action == 'scanStarted': pass else: logger.debug("Unknown dispatch action, '%s'." % action) except Exception as ex: message = utilities.createError(ex) logger.fatal(message) def run(self): startup_delay = utilities.getSettingAsInt('startup_delay') if startup_delay: logger.debug("Delaying startup by %d seconds." % startup_delay) xbmc.sleep(startup_delay * 1000) logger.debug("Service thread starting.") # purge queue before doing anything self.dispatchQueue.purge() # setup event driven classes self.Player = traktPlayer(action=self._dispatchQueue) self.Monitor = traktMonitor(action=self._dispatchQueue) # init traktapi class globals.traktapi = traktAPI() # init sync thread self.syncThread = syncThread() # init scrobbler class self.scrobbler = Scrobbler(globals.traktapi) # start loop for events while not xbmc.abortRequested: while len(self.dispatchQueue) and (not xbmc.abortRequested): data = self.dispatchQueue.get() logger.debug("Queued dispatch: %s" % data) self._dispatch(data) if xbmc.Player().isPlayingVideo(): self.scrobbler.update() xbmc.sleep(500) # we are shutting down logger.debug("Beginning shut down.") # delete player/monitor del self.Player del self.Monitor # check if sync thread is running, if so, join it. if self.syncThread.isAlive(): self.syncThread.join() def doManualRating(self, data): action = data['action'] media_type = data['media_type'] summaryInfo = None if not utilities.isValidMediaType(media_type): logger.debug( "doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action)) return if not data['action'] in ['rate', 'unrate']: logger.debug("doManualRating(): Unknown action passed.") return if 'dbid' in data: logger.debug( "Getting data for manual %s of library '%s' with ID of '%s'" % (action, media_type, data['dbid'])) elif 'remoteitd' in data: if 'season' in data: logger.debug( "Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'." % (action, media_type, data['season'], data['episode'], data['remoteid'])) else: logger.debug( "Getting data for manual %s of non-library '%s' with ID of '%s'" % (action, media_type, data['remoteid'])) if utilities.isEpisode(media_type): summaryInfo = globals.traktapi.getEpisodeSummary( data['trakt'], data['season'], data['episode']) elif utilities.isShow(media_type): summaryInfo = globals.traktapi.getShowSummary(data['imdbnumber']) elif utilities.isMovie(media_type): summaryInfo = globals.traktapi.getMovieSummary(data['imdbnumber']) if not summaryInfo is None: if utilities.isMovie(media_type) or utilities.isShow(media_type): summaryInfo['xbmc_id'] = data['dbid'] if action == 'rate': if not 'rating' in data: rateMedia(media_type, summaryInfo) else: rateMedia(media_type, summaryInfo, rating=data['rating']) else: logger.debug( "doManualRating(): Summary info was empty, possible problem retrieving data from Trakt.tv" ) def doMarkWatched(self, data): media_type = data['media_type'] markedNotification = utilities.getSettingAsBool( 'show_marked_notification') if utilities.isMovie(media_type): summaryInfo = globals.traktapi.getMovieSummary(data['id']) if summaryInfo: if not summaryInfo['watched']: s = utilities.getFormattedItemName(media_type, summaryInfo) logger.debug( "doMarkWatched(): '%s' is not watched on Trakt, marking it as watched." % s) movie = { 'imdb_id': data['id'], 'title': summaryInfo['title'], 'year': summaryInfo['year'], 'plays': 1, 'last_played': int(time()) } params = {'movies': [movie]} logger.debug("doMarkWatched(): %s" % str(params)) result = globals.traktapi.updateSeenMovie(params) if result: if markedNotification: utilities.notification(utilities.getString(32113), s) else: utilities.notification(utilities.getString(32114), s) elif utilities.isEpisode(media_type): summaryInfo = globals.traktapi.getEpisodeSummary( data['id'], data['season'], data['episode']) if summaryInfo: if not summaryInfo['episode']['watched']: s = utilities.getFormattedItemName(media_type, summaryInfo) logger.debug( "doMarkWathced(): '%s' is not watched on Trakt, marking it as watched." % s) params = { 'imdb_id': summaryInfo['ids']['imdb_id'], 'tvdb_id': summaryInfo['ids']['tvdb_id'], 'title': summaryInfo['title'], 'year': summaryInfo['year'], 'episodes': [{ 'season': data['season'], 'episode': data['episode'] }] } logger.debug("doMarkWatched(): %s" % str(params)) result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification(utilities.getString(32113), s) else: utilities.notification(utilities.getString(32114), s) elif utilities.isSeason(media_type): showInfo = globals.traktapi.getShowSummary(data['id']) if not showInfo: return summaryInfo = globals.traktapi.getSeasonInfo( data['id'], data['season']) if summaryInfo: showInfo['season'] = data['season'] s = utilities.getFormattedItemName(media_type, showInfo) params = { 'imdb_id': summaryInfo['ids']['imdb'], 'tvdb_id': summaryInfo['ids']['tvdb'], 'title': showInfo['title'], 'year': showInfo['year'], 'episodes': [] } for ep in summaryInfo: if ep['episode'] in data['episodes']: if not ep['watched']: params['episodes'].append({ 'season': ep['season'], 'episode': ep['episode'] }) logger.debug( "doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched." % (showInfo['title'], data['season'], len(params['episodes']))) if len(params['episodes']) > 0: logger.debug("doMarkWatched(): %s" % str(params)) result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification( utilities.getString(32113), utilities.getString(32115) % (len(params['episodes']), s)) else: utilities.notification( utilities.getString(32114), utilities.getString(32115) % (len(params['episodes']), s)) elif utilities.isShow(media_type): summaryInfo = globals.traktapi.getShowSummary(data['id'], extended=True) if summaryInfo: s = utilities.getFormattedItemName(media_type, summaryInfo) params = { 'imdb_id': summaryInfo['ids']['imdb'], 'tvdb_id': summaryInfo['ids']['tvdb'], 'title': summaryInfo['title'], 'year': summaryInfo['year'], 'episodes': [] } for season in summaryInfo['seasons']: for ep in season['episodes']: if str(season['season']) in data['seasons']: if ep['episode'] in data['seasons'][str( season['season'])]: if not ep['watched']: params['episodes'].append({ 'season': ep['season'], 'episode': ep['episode'] }) logger.debug( "doMarkWatched(): '%s' has %d episode(s) that are going to be marked as watched." % (summaryInfo['title'], len(params['episodes']))) if len(params['episodes']) > 0: logger.debug("doMarkWatched(): %s" % str(params)) result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification( utilities.getString(32113), utilities.getString(32115) % (len(params['episodes']), s)) else: utilities.notification( utilities.getString(32114), utilities.getString(32115) % (len(params['episodes']), s)) def doSync(self, manual=False, silent=False, library="all"): self.syncThread = syncThread(manual, silent, library) self.syncThread.start()
class traktService: scrobbler = None tagger = None updateTagsThread = None watcher = None syncThread = None dispatchQueue = queue.SqliteQueue() _interval = 10 * 60 # how often to send watching call def __init__(self): threading.Thread.name = 'trakt' def _dispatchQueue(self, data): utilities.Debug("Queuing for dispatch: %s" % data) self.dispatchQueue.append(data) def _dispatch(self, data): utilities.Debug("Dispatch: %s" % data) action = data['action'] if action == 'started': del data['action'] self.scrobbler.playbackStarted(data) self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() elif action == 'ended' or action == 'stopped': self.scrobbler.playbackEnded() if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() self.watcher = None elif action == 'paused': self.scrobbler.playbackPaused() elif action == 'resumed': self.scrobbler.playbackResumed() elif action == 'seek' or action == 'seekchapter': self.scrobbler.playbackSeek() elif action == 'databaseUpdated': self.doSync() elif action == 'scanStarted': pass elif action == 'settingsChanged': utilities.Debug("Settings changed, reloading.") globals.traktapi.updateSettings() self.tagger.updateSettings() elif action == 'markWatched': del data['action'] self.doMarkWatched(data) elif action == 'manualRating': ratingData = data['ratingData'] self.doManualRating(ratingData) elif action == 'manualSync': if not self.syncThread.isAlive(): utilities.Debug("Performing a manual sync.") self.doSync(manual=True) else: utilities.Debug("There already is a sync in progress.") elif action == 'updatetags': if self.updateTagsThread and self.updateTagsThread.isAlive(): utilities.Debug("Currently updating tags already.") else: self.updateTagsThread = threading.Thread( target=self.tagger.updateTagsFromTrakt, name="trakt-updatetags") self.updateTagsThread.start() elif action == 'managelists': self.tagger.manageLists() elif action == 'itemlists': del data['action'] self.tagger.itemLists(data) elif action == 'addtolist': del data['action'] list = data['list'] del data['list'] self.tagger.manualAddToList(list, data) elif action == 'removefromlist': del data['action'] list = data['list'] del data['list'] self.tagger.manualRemoveFromList(list, data) else: utilities.Debug("Unknown dispatch action, '%s'." % action) def run(self): startup_delay = utilities.getSettingAsInt('startup_delay') if startup_delay: utilities.Debug("Delaying startup by %d seconds." % startup_delay) xbmc.sleep(startup_delay * 1000) utilities.Debug("Service thread starting.") # setup event driven classes self.Player = traktPlayer(action=self._dispatchQueue) self.Monitor = traktMonitor(action=self._dispatchQueue) # init traktapi class globals.traktapi = traktAPI() # init sync thread self.syncThread = syncThread() # init scrobbler class self.scrobbler = Scrobbler(globals.traktapi) # init tagging class self.tagger = Tagger(globals.traktapi) # purge queue self.dispatchQueue.purge() # start loop for events while (not xbmc.abortRequested): while len(self.dispatchQueue) and (not xbmc.abortRequested): data = self.dispatchQueue.get() utilities.Debug("Queued dispatch: %s" % data) self._dispatch(data) if xbmc.Player().isPlayingVideo(): self.scrobbler.update() xbmc.sleep(500) # we are shutting down utilities.Debug("Beginning shut down.") # check if watcher is set and active, if so, cancel it. if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() # delete player/monitor del self.Player del self.Monitor # check update tags thread. if self.updateTagsThread and self.updateTagsThread.isAlive(): self.updateTagsThread.join() # check if sync thread is running, if so, join it. if self.syncThread.isAlive(): self.syncThread.join() def doWatching(self): # check if we're still playing a video if not xbmc.Player().isPlayingVideo(): self.watcher = None return # call watching method self.scrobbler.watching() # start a new timer thread self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() def doManualRating(self, data): action = data['action'] media_type = data['media_type'] summaryInfo = None if not utilities.isValidMediaType(media_type): utilities.Debug( "doManualRating(): Invalid media type '%s' passed for manual %s." % (media_type, action)) return if not data['action'] in ['rate', 'unrate']: utilities.Debug("doManualRating(): Unknown action passed.") return if 'dbid' in data: utilities.Debug( "Getting data for manual %s of library '%s' with ID of '%s'" % (action, media_type, data['dbid'])) elif 'remoteitd' in data: if 'season' in data: utilities.Debug( "Getting data for manual %s of non-library '%s' S%02dE%02d, with ID of '%s'." % (action, media_type, data['season'], data['episode'], data['remoteid'])) else: utilities.Debug( "Getting data for manual %s of non-library '%s' with ID of '%s'" % (action, media_type, data['remoteid'])) if utilities.isEpisode(media_type): summaryInfo = globals.traktapi.getEpisodeSummary( data['tvdb_id'], data['season'], data['episode']) elif utilities.isShow(media_type): summaryInfo = globals.traktapi.getShowSummary(data['imdbnumber']) elif utilities.isMovie(media_type): summaryInfo = globals.traktapi.getMovieSummary(data['imdbnumber']) if not summaryInfo is None: if utilities.isMovie(media_type) or utilities.isShow(media_type): summaryInfo['xbmc_id'] = data['dbid'] if action == 'rate': if not 'rating' in data: rateMedia(media_type, summaryInfo) else: rateMedia(media_type, summaryInfo, rating=data['rating']) elif action == 'unrate': rateMedia(media_type, summaryInfo, unrate=True) else: utilities.Debug( "doManualRating(): Summary info was empty, possible problem retrieving data from trakt.tv" ) def doMarkWatched(self, data): media_type = data['media_type'] simulate = utilities.getSettingAsBool('simulate_sync') markedNotification = utilities.getSettingAsBool( 'show_marked_notification') if utilities.isMovie(media_type): summaryInfo = globals.traktapi.getMovieSummary(data['id']) if summaryInfo: if not summaryInfo['watched']: s = utilities.getFormattedItemName(media_type, summaryInfo) utilities.Debug( "doMarkWatched(): '%s' is not watched on trakt, marking it as watched." % s) movie = {} movie['imdb_id'] = data['id'] movie['title'] = summaryInfo['title'] movie['year'] = summaryInfo['year'] movie['plays'] = 1 movie['last_played'] = int(time()) params = {'movies': [movie]} utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenMovie(params) if result: if markedNotification: utilities.notification( utilities.getString(1550), s) else: utilities.notification(utilities.getString(1551), s) else: if markedNotification: utilities.notification(utilities.getString(1550), s) elif utilities.isEpisode(media_type): summaryInfo = globals.traktapi.getEpisodeSummary( data['id'], data['season'], data['episode']) if summaryInfo: if not summaryInfo['episode']['watched']: s = utilities.getFormattedItemName(media_type, summaryInfo) utilities.Debug( "doMarkWathced(): '%s' is not watched on trakt, marking it as watched." % s) params = {} params['imdb_id'] = summaryInfo['show']['imdb_id'] params['tvdb_id'] = summaryInfo['show']['tvdb_id'] params['title'] = summaryInfo['show']['title'] params['year'] = summaryInfo['show']['year'] params['episodes'] = [{ 'season': data['season'], 'episode': data['episode'] }] utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification( utilities.getString(1550), s) else: utilities.notification(utilities.getString(1551), s) else: if markedNotification: utilities.notification(utilities.getString(1550), s) elif utilities.isSeason(media_type): showInfo = globals.traktapi.getShowSummary(data['id']) if not showInfo: return summaryInfo = globals.traktapi.getSeasonInfo( data['id'], data['season']) if summaryInfo: showInfo['season'] = data['season'] s = utilities.getFormattedItemName(media_type, showInfo) params = {} params['imdb_id'] = showInfo['imdb_id'] params['tvdb_id'] = showInfo['tvdb_id'] params['title'] = showInfo['title'] params['year'] = showInfo['year'] params['episodes'] = [] for ep in summaryInfo: if ep['episode'] in data['episodes']: if not ep['watched']: params['episodes'].append({ 'season': ep['season'], 'episode': ep['episode'] }) utilities.Debug( "doMarkWatched(): '%s - Season %d' has %d episode(s) that are going to be marked as watched." % (showInfo['title'], data['season'], len(params['episodes']))) if len(params['episodes']) > 0: utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification( utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) else: utilities.notification( utilities.getString(1551), utilities.getString(1552) % (len(params['episodes']), s)) else: if markedNotification: utilities.notification( utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) elif utilities.isShow(media_type): summaryInfo = globals.traktapi.getShowSummary(data['id'], extended=True) if summaryInfo: s = utilities.getFormattedItemName(media_type, summaryInfo) params = {} params['imdb_id'] = summaryInfo['imdb_id'] params['tvdb_id'] = summaryInfo['tvdb_id'] params['title'] = summaryInfo['title'] params['year'] = summaryInfo['year'] params['episodes'] = [] for season in summaryInfo['seasons']: for ep in season['episodes']: if str(season['season']) in data['seasons']: if ep['episode'] in data['seasons'][str( season['season'])]: if not ep['watched']: params['episodes'].append({ 'season': ep['season'], 'episode': ep['episode'] }) utilities.Debug( "doMarkWatched(): '%s' has %d episode(s) that are going to be marked as watched." % (summaryInfo['title'], len(params['episodes']))) if len(params['episodes']) > 0: utilities.Debug("doMarkWatched(): %s" % str(params)) if not simulate: result = globals.traktapi.updateSeenEpisode(params) if result: if markedNotification: utilities.notification( utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) else: utilities.notification( utilities.getString(1551), utilities.getString(1552) % (len(params['episodes']), s)) else: if markedNotification: utilities.notification( utilities.getString(1550), utilities.getString(1552) % (len(params['episodes']), s)) def doSync(self, manual=False): self.syncThread = syncThread(manual) self.syncThread.start()
class traktService: scrobbler = None watcher = None syncThread = None dispatchQueue = Queue.Queue() _interval = 10 * 60 # how often to send watching call def __init__(self): threading.Thread.name = 'trakt' def _dispatchQueue(self, data): utilities.Debug("Queuing for dispatch: %s" % data) self.dispatchQueue.put(data) def _dispatch(self, data): utilities.Debug("Dispatch: %s" % data) action = data['action'] if action == 'started': del data['action'] self.scrobbler.playbackStarted(data) self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() elif action == 'ended' or action == 'stopped': self.scrobbler.playbackEnded() if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() self.watcher = None elif action == 'paused': self.scrobbler.playbackPaused() elif action == 'resumed': self.scrobbler.playbackResumed() elif action == 'seek' or action == 'seekchapter': self.scrobbler.playbackSeek() elif action == 'databaseUpdated': self.doSync() elif action == 'scanStarted': pass elif action == 'settingsChanged': utilities.Debug("Settings changed, reloading.") globals.traktapi.updateSettings() else: utilities.Debug("Unknown dispatch action, '%s'." % action) def run(self): startup_delay = utilities.getSettingAsInt('startup_delay') if startup_delay: utilities.Debug("Delaying startup by %d seconds." % startup_delay) xbmc.sleep(startup_delay * 1000) utilities.Debug("Service thread starting.") # setup event driven classes self.Player = traktPlayer(action = self._dispatchQueue) self.Monitor = traktMonitor(action = self._dispatchQueue) # init traktapi class globals.traktapi = traktAPI() # init sync thread self.syncThread = syncThread() # init scrobbler class self.scrobbler = Scrobbler(globals.traktapi) # start loop for events while (not xbmc.abortRequested): while not self.dispatchQueue.empty() and (not xbmc.abortRequested): data = self.dispatchQueue.get() utilities.Debug("Queued dispatch: %s" % data) self._dispatch(data) # check if we were tasked to do a manual sync if utilities.getPropertyAsBool('traktManualSync'): if not self.syncThread.isAlive(): utilities.Debug("Performing a manual sync.") self.doSync(manual=True) else: utilities.Debug("There already is a sync in progress.") utilities.clearProperty('traktManualSync') if xbmc.Player().isPlayingVideo(): self.scrobbler.update() xbmc.sleep(500) # we are shutting down utilities.Debug("Beginning shut down.") # check if watcher is set and active, if so, cancel it. if self.watcher: if self.watcher.isAlive(): self.watcher.cancel() # delete player/monitor del self.Player del self.Monitor # check if sync thread is running, if so, join it. if self.syncThread.isAlive(): self.syncThread.join() def doWatching(self): # check if we're still playing a video if not xbmc.Player().isPlayingVideo(): self.watcher = None return # call watching method self.scrobbler.watching() # start a new timer thread self.watcher = threading.Timer(self._interval, self.doWatching) self.watcher.name = "trakt-watching" self.watcher.start() def doSync(self, manual=False): self.syncThread = syncThread(manual) self.syncThread.start()