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
Beispiel #2
0
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
Beispiel #6
0
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))