public EpisodeMatch navigate(EpisodeMatch episode, Pointer offset) {
        Path episodesPath = tvPath.getEpisodesPath(episode.getShow(), episode.getSeason());
        Range episodeRange = episode.getEpisodesAsRange();
        if(episodesPath == null) {
            boolean isNavigateSeason = offset == Pointer.PREV && (episodeRange.getStart() - 1) < 1;
            return isNavigateSeason ? navigateSeason(episode, offset) : null;
        }
        int episodeNoBound = (offset == Pointer.NEXT) ? episodeRange.getEnd() : episodeRange.getStart();
        EpisodeMatch curMatch = tvEpisodeMatcher.matchEpisode(episodesPath, episodeNoBound);
        if(curMatch != null) {
            episodeRange = curMatch.getEpisodesAsRange();
            episodeNoBound = (offset == Pointer.NEXT) ? episodeRange.getEnd() : episodeRange.getStart();
        }
        EpisodeMatch m = tvEpisodeMatcher.matchEpisode(episodesPath, episodeNoBound + offset.value());
        if(m != null || offset == Pointer.CUR) { 
            return m;
        }
        // check another offset episode to see if it's missing or likely to be end of season
        if(tvEpisodeMatcher.matchEpisode(episodesPath, episodeNoBound + (2 * offset.value())) != null) {
            return null; // found extra offset episode so dont skip to offset season
        }
        return navigateSeason(episode, offset);
    }