def get_upnext(self, show_id, response_only=False, last_updated=None): items = [] if not self.authorize(): return items cache_refresh = self.get_upnext_cache_refresh(show_id, last_updated) request = 'shows/{0}/progress/watched'.format(show_id) response = self.get_request(request, cache_refresh=cache_refresh, cache_days=1) reset_at = utils.convert_timestamp(response.get('reset_at')) if response.get('reset_at') else None seasons = response.get('seasons', []) for season in seasons: s_num = season.get('number') for episode in season.get('episodes', []): item = None e_num = episode.get('number') if episode.get('completed'): if reset_at and utils.convert_timestamp(episode.get('last_watched_at')) < reset_at: item = (s_num, e_num) else: item = (s_num, e_num) if item: if response_only: # utils.kodi_log(u'Up Next {} Episodes:\nFound next episode - S{}E{}'.format(show_id, s_num, e_num), 1) return response items.append(item) if not response_only: return items if items else [(1, 1)]
def get_upnext(self, show_id, response_only=False): items = [] if not self.authorize(): return items request = 'shows/{0}/progress/watched'.format(show_id) response = self.get_response_json(request) reset_at = utils.convert_timestamp( response.get('reset_at')) if response.get('reset_at') else None seasons = response.get('seasons', []) for season in seasons: s_num = season.get('number') for episode in season.get('episodes', []): item = None e_num = episode.get('number') if episode.get('completed'): if reset_at and utils.convert_timestamp( episode.get('last_watched_at')) < reset_at: item = (s_num, e_num) else: item = (s_num, e_num) if item: if response_only: return response items.append(item) if not response_only: return items if items else [(1, 1)]
def get_upnext_cache_refresh(self, show_id, last_updated): if not last_updated: # No last Trakt update date so refresh cache return True # Refresh cache ts_last = utils.convert_timestamp(last_updated) if not ts_last: return True # Timestamp doesn't convert so refresh cache cache_name = '{0}.trakt.show.{1}.last_updated'.format(self.cache_name, show_id) ts_prev = utils.convert_timestamp(self.get_cache(cache_name)) if not ts_prev: # No previous update date or cant convert save value to timestamp so refresh return self.set_cache(last_updated, cache_name) # Set the cache date and refresh cache if ts_prev < ts_last: # Changes on Trakt since previous update date so refresh cache return self.set_cache(last_updated, cache_name) # Set the cache date and refresh cache
def run(self): self.kodimonitor.waitForAbort( 450) # Delay start-up to give time for datetime python module self.nexttime = datetime.datetime.combine( datetime.datetime.today(), datetime.time(utils.try_parse_int( self.update_hour))) # Get today at hour self.lasttime = xbmc.getInfoLabel( 'Skin.String(TMDbHelper.AutoUpdate.LastTime)') # Get last update self.lasttime = utils.convert_timestamp( self.lasttime) if self.lasttime else None if self.lasttime and self.lasttime > self.nexttime: self.nexttime += datetime.timedelta( hours=24) # Already updated today so set for tomorrow while not self.kodimonitor.abortRequested( ) and not self.exit and self.poll_time: if self.addon.getSettingBool('library_autoupdate'): if datetime.datetime.now( ) > self.nexttime: # Scheduled time has past so lets update xbmc.executebuiltin( 'RunScript(plugin.video.themoviedb.helper,library_autoupdate)' ) xbmc.executebuiltin( 'Skin.SetString(TMDbHelper.AutoUpdate.LastTime,{})'. format(datetime.datetime.now().strftime( "%Y-%m-%dT%H:%M:%S"))) self.nexttime += datetime.timedelta( hours=24) # Set next update for tomorrow self.kodimonitor.waitForAbort(self.poll_time)
def get_trakt_watched(self, trakt_watched=None): if not trakt_watched: return key = 'movie' if self.infolabels.get( 'mediatype') == 'movie' else 'show' item = utils.get_dict_in_list(trakt_watched, 'tmdb', utils.try_parse_int(self.tmdb_id), [key, 'ids']) if not item: return if self.infolabels.get('mediatype') == 'episode': found_ep = None for s in item.get('seasons', []): if s.get('number', -2) == utils.try_parse_int( self.infolabels.get('season', -1)): for ep in s.get('episodes', []): if ep.get('number', -2) == utils.try_parse_int( self.infolabels.get('episode', -1)): found_ep = item = ep break break if not found_ep: return lastplayed = utils.convert_timestamp(item.get('last_watched_at')) self.infolabels['lastplayed'] = lastplayed.strftime( '%Y-%m-%d %H:%M:%S') if lastplayed else None self.infolabels['playcount'] = item.get('plays', 0) self.infolabels['overlay'] = 5 if item.get('plays') else 4
def get_calendar_properties(self, item, i): # Create our airing properties air_date = utils.convert_timestamp(i.get('first_aired'), utc_convert=True) item.infolabels['premiered'] = air_date.strftime('%Y-%m-%d') item.infolabels['year'] = air_date.strftime('%Y') item.infoproperties['air_date'] = utils.get_region_date( air_date, 'datelong') item.infoproperties['air_time'] = utils.get_region_date( air_date, 'time') item.infoproperties['air_day'] = air_date.strftime('%A') item.infoproperties['air_day_short'] = air_date.strftime('%a') item.infoproperties['air_date_short'] = air_date.strftime('%d %b') # Do some fallback properties in-case TMDb doesn't have info item.infolabels['title'] = item.label = i.get('episode', {}).get('title') item.infolabels['episode'] = item.infolabels.get('episode') or i.get( 'episode', {}).get('number') item.infolabels['season'] = item.infolabels.get('season') or i.get( 'episode', {}).get('season') item.infolabels['tvshowtitle'] = i.get('show', {}).get('title') item.infolabels['duration'] = item.infolabels.get( 'duration') or utils.try_parse_int( i.get('episode', {}).get('runtime', 0)) * 60 item.infolabels['plot'] = item.infolabels.get('plot') or i.get( 'episode', {}).get('overview') item.infolabels['mpaa'] = item.infolabels.get('mpaa') or i.get( 'show', {}).get('certification') return item
def run(self): xbmc.Monitor().waitForAbort(120) if self.addon.getSettingString('trakt_token'): _homewindow.setProperty('TMDbHelper.TraktIsAuth', 'True') self.get_trakt_usernameslug() xbmc.Monitor().waitForAbort(540) # Wait a bit before updating self.nexttime = datetime.datetime.combine( datetime.datetime.today(), datetime.time(utils.try_parse_int( self.update_hour))) # Get today at hour self.lasttime = xbmc.getInfoLabel( 'Skin.String(TMDbHelper.AutoUpdate.LastTime)') # Get last update self.lasttime = utils.convert_timestamp( self.lasttime) if self.lasttime else None if self.lasttime and self.lasttime > self.nexttime: self.nexttime += datetime.timedelta( hours=24) # Already updated today so set for tomorrow while not xbmc.Monitor().abortRequested( ) and not self.exit and self.poll_time: if self.addon.getSettingBool('library_autoupdate'): if datetime.datetime.now( ) > self.nexttime: # Scheduled time has past so lets update xbmc.executebuiltin( 'RunScript(plugin.video.themoviedb.helper,library_autoupdate)' ) xbmc.executebuiltin( 'Skin.SetString(TMDbHelper.AutoUpdate.LastTime,{})'. format(datetime.datetime.now().strftime( "%Y-%m-%dT%H:%M:%S"))) self.nexttime += datetime.timedelta( hours=24) # Set next update for tomorrow xbmc.Monitor().waitForAbort(self.poll_time)
def get_calendar_episodes(self, startdate=0, days=1, limit=25): items = [] if not self.tmdb or not self.authorize(): return items date = datetime.datetime.today() + datetime.timedelta(days=startdate) response = TraktAPI().get_calendar( 'shows', True, start_date=date.strftime('%Y-%m-%d'), days=days) if not response: return items for i in response[-limit:]: episode = i.get('episode', {}).get('number') season = i.get('episode', {}).get('season') tmdb_id = i.get('show', {}).get('ids', {}).get('tmdb') item = ListItem(library=self.library, **self.tmdb.get_detailed_item(itemtype='tv', tmdb_id=tmdb_id, season=season, episode=episode)) item.tmdb_id, item.season, item.episode = tmdb_id, season, episode item.infolabels['title'] = item.label = i.get('episode', {}).get('title') air_date = utils.convert_timestamp(i.get( 'first_aired', '')) + datetime.timedelta(hours=self.utc_offset) item.infolabels['premiered'] = air_date.strftime('%Y-%m-%d') item.infolabels['year'] = air_date.strftime('%Y') item.infoproperties['air_time'] = air_date.strftime('%I:%M %p') items.append(item) return items
def get_upnext_cache_refresh(self, show_id, last_updated): if not last_updated: # No last Trakt update date so refresh cache # utils.kodi_log(u'Up Next {} Episodes:\nNo last Trakt update date. Refreshing cache...'.format(show_id), 1) return True # Refresh cache cache_name = '{0}.trakt.show.{1}.last_updated'.format( self.cache_name, show_id) prev_updated = self.get_cache(cache_name) if not prev_updated: # No previous update date so refresh cache # utils.kodi_log(u'Up Next {} Episodes:\nNo previous update date. Refreshing cache...'.format(show_id), 1) return self.set_cache( last_updated, cache_name) # Set the cache date and refresh cache if utils.convert_timestamp(prev_updated) < utils.convert_timestamp( last_updated ): # Changes on Trakt since previous update date so refresh cache # utils.kodi_log(u'Up Next {} Episodes:\nChanges on Trakt since previous update date. Refreshing cache...'.format(show_id), 1) return self.set_cache( last_updated, cache_name) # Set the cache date and refresh cache
def library_addtvshow(basedir=None, folder=None, url=None, tmdb_id=None, tvdb_id=None, imdb_id=None, p_dialog=None): if not basedir or not folder or not url: return nfo_tmdbid = library_getnfo_tmdbid(basedir, folder) # Check the nfo file in the folder to make sure it matches the TMDB ID if nfo_tmdbid and utils.try_parse_int(nfo_tmdbid) != utils.try_parse_int(tmdb_id): folder += ' (TMDB {})'.format(tmdb_id) # If different tvshow with same name exists create new folder with TMDB ID added details_tvshow = _plugin.tmdb.get_request_sc('tv', tmdb_id) # Get base tv show if not details_tvshow: return library_create_nfo('tv', tmdb_id, folder, basedir=basedir) # Create .nfo for tvshow seasons = [i.get('season_number') for i in details_tvshow.get('seasons', []) if i.get('season_number', 0) != 0] # Don't get specials s_count, s_total = 0, len(seasons) # Used to update p_dialog progress for season in seasons: s_count += 1 season_name = u'Season {}'.format(season) # Originally made a bad choice here to localise season name but reverted that now if p_dialog: # Update our progress dialog p_dialog_val = (s_count * 100) // s_total p_dialog_msg = u'Adding {} - {} to library...'.format(details_tvshow.get('original_name'), season_name) p_dialog.update(p_dialog_val, message=p_dialog_msg) details_season = _plugin.tmdb.get_request_sc('tv', tmdb_id, 'season', season) # Get season if not details_season: return episodes = [i for i in details_season.get('episodes', []) if i.get('episode_number', 0) != 0] # Only get non-special seasons e_count, e_total = 0, len(episodes) # Used to update p_dialog progress for episode in episodes: e_count += 1 episode_name = 'S{:02d}E{:02d} - {}'.format( utils.try_parse_int(season), utils.try_parse_int(episode.get('episode_number')), utils.validify_filename(episode.get('name'))) # Skip future episodes if _addon.getSettingBool('hide_unaired_episodes'): if not episode.get('air_date') or utils.convert_timestamp(episode.get('air_date'), "%Y-%m-%d", 10) > datetime.datetime.now(): p_dialog.update((e_count * 100) // e_total, message=u'{} not aired yet. Skipping...'.format(episode_name)) if p_dialog else None continue # Check if item has already been added if _plugin.get_db_info(info='dbid', tmdbtype='episode', imdb_id=imdb_id, tmdb_id=tmdb_id, season=season, episode=episode.get('episode_number')): utils.kodi_log(u'Add to Library\nFound {} - {} in library. Skipping...'.format(episode.get('showtitle'), episode_name)) p_dialog.update((e_count * 100) // e_total, message=u'Found {} in library. Skipping...'.format(episode_name)) if p_dialog else None continue p_dialog.update((e_count * 100) // e_total, message=u'Adding {} to library...'.format(episode_name)) if p_dialog else None episode_path = 'plugin://plugin.video.themoviedb.helper/?info=play&type=episode&islocal=True' episode_path += '&tmdb_id={}&season={}&episode={}'.format(tmdb_id, season, episode.get('episode_number')) library_createfile(episode_name, episode_path, folder, season_name, basedir=basedir)
def add_tvshow(basedir=None, folder=None, url=None, tmdb_id=None, tvdb_id=None, imdb_id=None, p_dialog=None, force=False): if not basedir or not folder or not url or not tmdb_id: return # Get our cached info cache_name = 'plugin.video.themoviedb.helper.library_autoupdate_tv.{}'.format(tmdb_id) cache_info = {} if force else _cache.get(cache_name) or {} cache_version = 7 # If there's already a folder for a different show with the same name then create a separate folder nfo_id = utils.get_tmdbid_nfo(basedir, folder) if folder in xbmcvfs.listdir(basedir)[0] else None if nfo_id and utils.try_parse_int(nfo_id) != utils.try_parse_int(tmdb_id): folder += ' (TMDB {})'.format(tmdb_id) # Only use cache info if version matches if not cache_info.get('version') or cache_info.get('version') != cache_version: cache_info = {} # If there is a next check value and it hasn't elapsed then skip the update next_check = cache_info.get('next_check') if next_check and utils.convert_timestamp(next_check, "%Y-%m-%d", 10) > datetime.datetime.today(): if _debuglogging: log_msg = cache_info.get('log_msg') or '' utils.kodi_log(u'Skipping updating {} (TMDB {})\nNext update {}{}'.format( cache_info.get('name'), tmdb_id, next_check, log_msg), 2) return # Get all seasons in the tvshow except specials details_tvshow = _plugin.tmdb.get_request('tv', tmdb_id, cache_days=1, append_to_response='external_ids') if not details_tvshow: return # Update IDs from detailed info tvdb_id = details_tvshow.get('external_ids', {}).get('tvdb_id') or tvdb_id imdb_id = details_tvshow.get('external_ids', {}).get('imdb_id') or imdb_id # Create the .nfo file in the folder create_nfo('tv', tmdb_id, folder, basedir=basedir) # Construct our cache object today_date = datetime.datetime.today().strftime('%Y-%m-%d') my_history = { 'version': cache_version, 'name': details_tvshow.get('name', ''), 'skipped': [], 'episodes': [], 'latest_season': 0, 'next_check': today_date, 'last_check': today_date, 'log_msg': ''} # Set the next check date for this show next_aired = details_tvshow.get('next_episode_to_air', {}) if next_aired and next_aired.get('air_date'): next_aired_dt = utils.convert_timestamp(next_aired.get('air_date'), "%Y-%m-%d", 10) if next_aired_dt > datetime.datetime.today(): if next_aired_dt < (datetime.datetime.today() + datetime.timedelta(days=7)): my_history['next_check'] = next_aired.get('air_date') my_history['log_msg'] = '\nShow had next aired date this week' # Check again on the next aired date elif next_aired_dt < (datetime.datetime.today() + datetime.timedelta(days=30)): my_next_check = datetime.datetime.today() + datetime.timedelta(days=7) my_history['next_check'] = my_next_check.strftime('%Y-%m-%d') my_history['log_msg'] = '\nShow has next aired date this month' # Check again in a week just to be safe in case air date changes else: my_next_check = datetime.datetime.today() + datetime.timedelta(days=30) my_history['next_check'] = my_next_check.strftime('%Y-%m-%d') my_history['log_msg'] = '\nShow has next aired date in more than a month' # Check again in a month just to be safe in case air date changes else: next_aired = None # Next aired was in the past for some reason so dont use that date last_aired = details_tvshow.get('last_episode_to_air', {}) if not next_aired and last_aired and last_aired.get('air_date'): last_aired_dt = utils.convert_timestamp(last_aired.get('air_date'), "%Y-%m-%d", 10) if last_aired_dt > (datetime.datetime.today() - datetime.timedelta(days=30)): my_next_check = datetime.datetime.today() + datetime.timedelta(days=1) my_history['next_check'] = my_next_check.strftime('%Y-%m-%d') my_history['log_msg'] = '\nShow aired in last month but no next aired date' # Show might be currently airing but just hasnt updated next date yet so check again tomorrow elif last_aired_dt > (datetime.datetime.today() - datetime.timedelta(days=90)): my_history['log_msg'] = '\nShow aired in last quarter but not in last month' my_next_check = datetime.datetime.today() + datetime.timedelta(days=7) my_history['next_check'] = my_next_check.strftime('%Y-%m-%d') # Show might be on a mid-season break so check again in a week for a return date elif details_tvshow.get('status') in ['Canceled', 'Ended']: my_history['log_msg'] = '\nShow was canceled or ended' my_next_check = datetime.datetime.today() + datetime.timedelta(days=30) my_history['next_check'] = my_next_check.strftime('%Y-%m-%d') # Show was canceled so check again in a month just to be safe else: my_history['log_msg'] = '\nShow last aired more than 3 months ago and no next aired date set' my_next_check = datetime.datetime.today() + datetime.timedelta(days=7) my_history['next_check'] = my_next_check.strftime('%Y-%m-%d') # Show hasnt aired in a while so check every week for a return date prev_added_eps = cache_info.get('episodes') or [] prev_skipped_eps = cache_info.get('skipped') or [] seasons = details_tvshow.get('seasons', []) s_total = len(seasons) for s_count, season in enumerate(seasons): # Skip special seasons if season.get('season_number', 0) == 0: if _debuglogging: utils.kodi_log(u'{} (TMDB {})\nSpecial Season. Skipping...'.format(details_tvshow.get('name'), tmdb_id), 2) s_total -= 1 continue season_name = u'Season {}'.format(season.get('season_number')) # Update our progress dialog if p_dialog: p_dialog_val = ((s_count + 1) * 100) // s_total p_dialog_msg = u'{} {} - {}...'.format(_addon.getLocalizedString(32167), details_tvshow.get('original_name'), season_name) p_dialog.update(p_dialog_val, message=p_dialog_msg) # If weve scanned before we only want to scan the most recent seasons (that have already started airing) latest_season = utils.try_parse_int(cache_info.get('latest_season', 0)) if utils.try_parse_int(season.get('season_number', 0)) < latest_season: if _debuglogging: utils.kodi_log(u'{} (TMDB {})\nPreviously Added {}. Skipping...'.format(details_tvshow.get('name'), tmdb_id, season_name), 2) continue # Get all episodes in the season except specials details_season = _plugin.tmdb.get_request('tv', tmdb_id, 'season', season.get('season_number'), cache_refresh=True) if not details_season: utils.kodi_log(u'{} (TMDB {})\nNo details found for {}. Skipping...'.format(details_tvshow.get('name'), tmdb_id, season_name)) return episodes = [i for i in details_season.get('episodes', []) if i.get('episode_number', 0) != 0] # Only get non-special seasons skipped_eps, future_eps, library_eps = [], [], [] for e_count, episode in enumerate(episodes): episode_name = 'S{:02d}E{:02d} - {}'.format( utils.try_parse_int(season.get('season_number')), utils.try_parse_int(episode.get('episode_number')), utils.validify_filename(episode.get('name'))) my_history['episodes'].append(episode_name) # Skip episodes we added in the past if episode_name in prev_added_eps: if episode_name not in prev_skipped_eps: if _debuglogging: skipped_eps.append(episode_name) continue # Skip future episodes if _addon.getSettingBool('hide_unaired_episodes'): air_date = utils.convert_timestamp(episode.get('air_date'), "%Y-%m-%d", 10) if not air_date or air_date > datetime.datetime.now(): if _debuglogging: future_eps.append(episode_name) my_history['skipped'].append(episode_name) continue # Check if item has already been added if _plugin.get_db_info(info='dbid', tmdbtype='episode', imdb_id=imdb_id, tmdb_id=tmdb_id, tvdb_id=tvdb_id, season=season.get('season_number'), episode=episode.get('episode_number')): if _debuglogging: library_eps.append(episode_name) continue # Update progress dialog if p_dialog: p_dialog.update(((e_count + 1) * 100) // len(episodes)) # Create our .strm file for the episode episode_path = 'plugin://plugin.video.themoviedb.helper/?info=play&type=episode&islocal=True' episode_path += '&tmdb_id={}&season={}&episode={}'.format(tmdb_id, season.get('season_number', 0), episode.get('episode_number')) create_file(episode_name, episode_path, folder, season_name, basedir=basedir) # Some logging of what we did if _debuglogging: klog_msg = u'{} (TMDB {}) - {} - Done!'.format(details_tvshow.get('name'), tmdb_id, season_name) if skipped_eps: klog_msg += u'\nSkipped Previously Added Episodes:\n{}'.format(skipped_eps) if library_eps: klog_msg += u'\nSkipped Episodes in Library:\n{}'.format(library_eps) if future_eps: klog_msg += u'\nSkipped Unaired Episodes:\n{}'.format(future_eps) utils.kodi_log(klog_msg, 2) # Store a season value of where we got up to if len(episodes) > 2: air_date = utils.convert_timestamp(season.get('air_date'), "%Y-%m-%d", 10) if air_date and air_date < datetime.datetime.now(): # Make sure the season has actually aired! my_history['latest_season'] = utils.try_parse_int(season.get('season_number')) # Store details about what we did into the cache _cache.set(cache_name, my_history, expiration=datetime.timedelta(days=120))