def library_createfile(filename, content, *args, **kwargs): """ Create the file and folder structure: filename=.strm file, content= content of file. *args = folders to create. """ file_ext = kwargs.pop('file_ext', 'strm') clean_url = kwargs.pop('clean_url', True) path = kwargs.pop('basedir', '') path = path.replace('\\', '/') if not path: utils.kodi_log(u'ADD LIBRARY -- No basedir specified!', 2) return content = library_cleancontent(content) if clean_url else content for folder in args: folder = utils.validify_filename(folder) path = '{}{}/'.format(path, folder) if not content: utils.kodi_log(u'ADD LIBRARY -- No content specified!', 2) return if not filename: utils.kodi_log(u'ADD LIBRARY -- No filename specified!', 2) return if not library_createpath(path): xbmcgui.Dialog().ok( xbmc.getLocalizedString(20444), _addon.getLocalizedString(32122) + ' [B]{}[/B]'.format(path), _addon.getLocalizedString(32123)) utils.kodi_log(u'ADD LIBRARY -- XBMCVFS unable to create path:\n{}'.format(path), 2) return filepath = '{}{}.{}'.format(path, utils.validify_filename(filename), file_ext) f = xbmcvfs.File(filepath, 'w') f.write(utils.try_encode_string(content)) f.close() utils.kodi_log(u'ADD LIBRARY -- Successfully added:\n{}\n{}'.format(filepath, content), 2) return filepath
def library_createfile(filename, content, *args, **kwargs): """ Create the file and folder structure: filename=.strm file, content= content of file. *args = folders to create. """ file_ext = kwargs.pop('file_ext', 'strm') path = kwargs.pop('basedir', '') path = path.replace('\\', '/') if not path: return utils.kodi_log('ADD LIBRARY -- No basedir specified!', 2) content = library_cleancontent(content) for folder in args: folder = utils.validify_filename(folder) path = '{}{}/'.format(path, folder) if not content: return utils.kodi_log('ADD LIBRARY -- No content specified!', 2) if not filename: return utils.kodi_log('ADD LIBRARY -- No filename specified!', 2) if not library_createpath(path): xbmcgui.Dialog().ok( 'Add to Library', 'XBMCVFS reports unable to create path [B]{}[/B]'.format(path), 'If error persists and the folders are created correctly, ' 'please disable folder path creation checking in TMDBHelper settings.') return utils.kodi_log('ADD LIBRARY -- XBMCVFS unable to create path:\n{}'.format(path), 2) filepath = '{}{}.{}'.format(path, utils.validify_filename(filename), file_ext) f = xbmcvfs.File(filepath, 'w') f.write(str(content)) f.close() utils.kodi_log('ADD LIBRARY -- Successfully added:\n{}\n{}'.format(filepath, content), 2)
def library(): with utils.busy_dialog(): title = utils.validify_filename(sys.listitem.getVideoInfoTag().getTitle()) dbtype = sys.listitem.getVideoInfoTag().getMediaType() basedir_movie = _addon.getSettingString('movies_library') or 'special://profile/addon_data/plugin.video.skin.info.provider/movies/' basedir_tv = _addon.getSettingString('tvshows_library') or 'special://profile/addon_data/plugin.video.skin.info.provider/tvshows/' auto_update = _addon.getSettingBool('auto_update') or False # Setup our folders and file names if dbtype == 'movie': folder = '{} ({})'.format(title, sys.listitem.getVideoInfoTag().getYear()) movie_name = '{} ({})'.format(title, sys.listitem.getVideoInfoTag().getYear()) library_createfile(movie_name, sys.listitem.getPath(), folder, basedir=basedir_movie) library_create_nfo('movie', sys.listitem.getProperty('tmdb_id'), folder, basedir=basedir_movie) xbmc.executebuiltin('UpdateLibrary(video, {})'.format(basedir_movie)) if auto_update else None elif dbtype == 'episode': folder = sys.listitem.getVideoInfoTag().getTVShowTitle() season_name = 'Season {}'.format(sys.listitem.getVideoInfoTag().getSeason()) episode_name = 'S{:02d}E{:02d} - {}'.format( utils.try_parse_int(sys.listitem.getVideoInfoTag().getSeason()), utils.try_parse_int(sys.listitem.getVideoInfoTag().getEpisode()), title) library_createfile(episode_name, sys.listitem.getPath(), folder, season_name, basedir=basedir_tv) library_create_nfo('tv', sys.listitem.getProperty('tvshow.tmdb_id'), folder, basedir=basedir_tv) xbmc.executebuiltin('UpdateLibrary(video, {})'.format(basedir_tv)) if auto_update else None elif dbtype == 'tvshow': folder = sys.listitem.getVideoInfoTag().getTVShowTitle() or title library_addtvshow( basedir=basedir_tv, folder=folder, url=sys.listitem.getPath(), tmdb_id=sys.listitem.getProperty('tmdb_id')) xbmc.executebuiltin('UpdateLibrary(video, {})'.format(basedir_tv)) if auto_update else None elif dbtype == 'season': folder = sys.listitem.getVideoInfoTag().getTVShowTitle() episodes = KodiLibrary().get_directory(sys.listitem.getPath()) season_name = 'Season {}'.format(sys.listitem.getVideoInfoTag().getSeason()) for episode in episodes: if not episode.get('episode'): continue # Skip special episodes E00 episode_path = library_cleancontent(episode.get('file')) episode_name = 'S{:02d}E{:02d} - {}'.format( utils.try_parse_int(episode.get('season')), utils.try_parse_int(episode.get('episode')), utils.validify_filename(episode.get('title'))) library_createfile(episode_name, episode_path, folder, season_name, basedir=basedir_tv) library_create_nfo('tv', sys.listitem.getProperty('tvshow.tmdb_id'), folder, basedir=basedir_tv) xbmc.executebuiltin('UpdateLibrary(video, {})'.format(basedir_tv)) if auto_update else None else: return
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 create_file(filename, content, *args, **kwargs): """ Create the file and folder structure: filename=.strm file, content= content of file. *args = folders to create. """ # Validify and build path path = kwargs.get('basedir', '').replace('\\', '/') # Convert MS-DOS style paths to UNIX style if not path: # Make sure we actually have a basedir return for folder in args: folder = utils.validify_filename(folder) path = '{}{}/'.format(path, folder) # Validify content of file if kwargs.get('clean_url', True): content = clean_content(content) if not content: return if not filename: return # Check that we can actually make the path and warn user about potential xbmcvfs false negative override if not utils.makepath(path): xbmcgui.Dialog().ok( xbmc.getLocalizedString(20444), '{} [B]{}[/B]\n{}'.format(_addon.getLocalizedString(32122), path, _addon.getLocalizedString(32123))) utils.kodi_log(u'XBMCVFS unable to create path:\n{}'.format(path), 2) return # Write out our file filepath = '{}{}.{}'.format(path, utils.validify_filename(filename), kwargs.get('file_ext', 'strm')) f = xbmcvfs.File(filepath, 'w') f.write(utils.try_encode_string(content)) f.close() utils.kodi_log(u'ADD LIBRARY -- Successfully added:\n{}\n{}'.format(filepath, content), 2) return filepath
def library_addtvshow(basedir=None, folder=None, url=None, tmdb_id=None): if not basedir or not folder or not url: return seasons = library_cleancontent(url, details='info=seasons') seasons = KodiLibrary().get_directory(seasons) library_create_nfo('tv', tmdb_id, folder, basedir=basedir) for season in seasons: if not season.get('season'): continue # Skip special seasons S00 season_name = 'Season {}'.format(season.get('season')) episodes = KodiLibrary().get_directory(season.get('file')) for episode in episodes: if not episode.get('episode'): continue # Skip special episodes E00 episode_path = library_cleancontent(episode.get('file')) episode_name = 'S{:02d}E{:02d} - {}'.format( utils.try_parse_int(episode.get('season')), utils.try_parse_int(episode.get('episode')), utils.validify_filename(episode.get('title'))) library_createfile(episode_name, episode_path, folder, season_name, basedir=basedir)
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 seasons = library_cleancontent_replacer(url, 'type=episode', 'type=tv') # Clean-up flatseasons seasons = library_cleancontent(seasons, details='info=seasons') seasons = KodiLibrary().get_directory(seasons) library_create_nfo('tv', tmdb_id, folder, basedir=basedir) s_count = 0 s_total = len(seasons) for season in seasons: s_count += 1 if not season.get('season'): continue # Skip special seasons S00 season_name = '{} {}'.format(xbmc.getLocalizedString(20373), season.get('season')) p_dialog.update((s_count * 100) // s_total, message=u'Adding {} - {} to library...'.format(season.get('showtitle'), season_name)) if p_dialog else None episodes = library_cleancontent_replacer(season.get('file'), 'type=episode', 'type=season') # Clean to prevent flatseasons episodes = library_cleancontent(episodes, details='info=episodes') episodes = KodiLibrary().get_directory(episodes) i_count = 0 i_total = len(episodes) for episode in episodes: i_count += 1 if not episode.get('episode'): continue # Skip special episodes E00 s_num = episode.get('season') e_num = episode.get('episode') episode_name = 'S{:02d}E{:02d} - {}'.format( utils.try_parse_int(s_num), utils.try_parse_int(e_num), utils.validify_filename(episode.get('title'))) if _plugin.get_db_info(info='dbid', tmdbtype='episode', imdb_id=imdb_id, tmdb_id=tmdb_id, season=s_num, episode=e_num): utils.kodi_log(u'Trakt List Add to Library\nFound {} - {} in library. Skipping...'.format(episode.get('showtitle'), episode_name)) p_dialog.update((i_count * 100) // i_total, message=u'Found {} in library. Skipping...'.format(episode_name)) if p_dialog else None continue # Skip added items p_dialog.update((i_count * 100) // i_total, message=u'Adding {} to library...'.format(episode_name)) if p_dialog else None episode_path = library_cleancontent(episode.get('file')) 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))