private List<GUITrailerListItem> SearchForLocalTrailers(MediaItem searchItem, string directory, string searchPattern)
        {
            var listItems = new List<GUITrailerListItem>();

            FileLog.Debug("Searching for local trailers in directory: '{0}', with search pattern: '{1}'", directory, searchPattern);

            // check if string replacements produced a bad search pattern
            if (searchPattern.Contains("**") || searchPattern.Contains("null"))
                return listItems;

            try
            {
                foreach (var file in Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly))
                {
                    // check it's a video file as defined by MediaPortal and User in MP Configuration
                    if (!MediaPortal.Util.Utils.IsVideo(file)) continue;

                    // check it's not a sample
                    if (Path.GetFileName(file).ToLowerInvariant().StartsWith("sample")) continue;

                    // check it's not the same file as the source
                    if (file.Equals(searchItem.FullPath, StringComparison.InvariantCultureIgnoreCase)) continue;

                    // check we have not already got this trailer matched
                    if (TrailerFiles.Contains(file)) continue;

                    FileLog.Debug("Found local trailer that matched search criteria: '{0}'", file);

                    var listItem = new GUITrailerListItem();

                    listItem.Label = Path.GetFileNameWithoutExtension(file);
                    listItem.Label2 = Translation.Local;
                    listItem.URL = file;
                    listItem.CurrentMedia = searchItem;

                    listItems.Add(listItem);

                    // store trailer file in case we are in 'aggressive' mode
                    TrailerFiles.Add(file);
                }
            }
            catch (Exception e)
            {
                FileLog.Error("Failed to get files from '{0}' with error: {1}", directory, e.Message);
            }

            return listItems;
        }
        private List<GUITrailerListItem> SearchMovieTrailers(MediaItem searchItem)
        {
            string searchTerm = string.Empty;
            var listItems = new List<GUITrailerListItem>();

            if (!string.IsNullOrEmpty(searchItem.TMDb))
            {
                searchTerm = searchItem.TMDb;
            }
            else if (!string.IsNullOrEmpty((searchItem.IMDb ?? string.Empty).Trim()))
            {
                var externalId = PluginSettings.IMDbIds.FirstOrDefault(t => t.ExternalId == searchItem.IMDb);
                if (externalId == null)
                {
                    // use the find method to lookup by external source id
                    FileLog.Debug("Searching themoviedb.org for all objects with IMDb ID '{0}'", searchItem.IMDb);

                    var findResults = TMDbAPI.TMDbFind(searchItem.IMDb, TMDbAPI.ExternalSource.imdb_id);
                    if (findResults == null || findResults.Movies == null || findResults.Movies.Count == 0)
                    {
                        FileLog.Warning("Not enough information to search for trailers from themoviedb.org, no matches found using IMDb ID");
                        return listItems;
                    }

                    // there should only be one
                    searchTerm = findResults.Movies.First().Id.ToString();

                    // cache id so we can use it again
                    PluginSettings.IMDbIds.Add(new PluginSettings.ExternalID { ExternalId = searchItem.IMDb, TmdbId = findResults.Movies.First().Id });
                }
                else
                {
                    FileLog.Debug("Found cached TMDb ID '{0}' for IMDb External ID: '{1}'", externalId.TmdbId.ToString(), searchItem.IMDb);
                    searchTerm = externalId.TmdbId.ToString();
                }
            }
            else if (!string.IsNullOrEmpty(searchItem.Title))
            {
                // we do the best we can with out any proper movie id's
                FileLog.Debug("Searching themoviedb.org for movie: Title: '{0}', Year: '{1}'", searchItem.Title, searchItem.Year);

                var searchResults = TMDbAPI.SearchMovies(searchItem.Title, language: "en", year: searchItem.Year <= 1900 ? null : searchItem.Year.ToString());
                if (searchResults == null || searchResults.TotalResults == 0)
                {
                    FileLog.Warning("No movies found, skipping search from the themoviedb.org.");
                    return listItems;
                }
                else
                {
                    foreach (var movie in searchResults.Results)
                    {
                        FileLog.Debug("Found movie: Title: '{0}', Original Title: '{1}', Release Date: '{2}', TMDb: '{3}', Popularity: '{4}'", movie.Title, movie.OriginalTitle, movie.ReleaseDate, movie.Id, movie.Popularity);
                    }
                }

                // get the movie id of the first result, this would be the most likely match (based on popularity)
                // we can think about providing a menu of choices as well based on demand
                searchTerm = searchResults.Results.First().Id.ToString();
                searchItem.TMDb = searchTerm;
            }
            else
            {
                FileLog.Warning("Not enough information to search for trailers from themoviedb.org, require IMDb ID, TMDb ID or Title+Year.");
                return listItems;
            }

            FileLog.Debug("Searching for movie trailers using search term '{0}' from themoviedb.org...", searchTerm);
            var trailers = GetMovieTrailersFromCache(searchTerm);
            if (trailers == null || trailers.Results == null)
            {
                FileLog.Error("Error getting movie trailers from themoviedb.org.");
                return listItems;
            }

            foreach (var trailer in trailers.Results)
            {
                var listItem = new GUITrailerListItem();

                string itemName = string.IsNullOrEmpty(trailer.Type) || trailer.Name.ToLowerInvariant().Contains(trailer.Type.ToLowerInvariant()) ? trailer.Name : string.Format("{0} - {1}", trailer.Name, trailer.Type);
                itemName = string.IsNullOrEmpty(trailer.Size) || itemName.ToLowerInvariant().Contains(trailer.Size.ToLowerInvariant()) ? itemName : string.Format("{0} ({1})", itemName, trailer.Size);
                if (PluginSettings.PreferredLanguage != "en")
                {
                    itemName = string.Format("{0} [{1}]", itemName, trailer.LanguageCode);
                }

                listItem.Label = itemName;
                listItem.Label2 = Localisation.Translation.Online;
                listItem.URL = WebUtils.GetYouTubeURL(trailer.Key);
                listItem.TVTag = trailer;
                listItem.IsOnlineItem = true;
                listItem.CurrentMedia = searchItem;

                listItems.Add(listItem);
            }

            FileLog.Info("Found {0} movie trailer(s) from themoviedb.org", trailers.Results.Count.ToString());

            return listItems;
        }
        private List<GUITrailerListItem> SearchShowTrailers(MediaItem searchItem)
        {
            string searchTerm = string.Empty;
            var listItems = new List<GUITrailerListItem>();

            if (!string.IsNullOrEmpty(searchItem.TMDb))
            {
                searchTerm = searchItem.TMDb;
            }
            else if (!string.IsNullOrEmpty(searchItem.TVDb))
            {
                // check if external id is cached
                var externalId = PluginSettings.TVDbIds.FirstOrDefault(t => t.ExternalId == searchItem.TVDb);
                if (externalId == null)
                {

                    // use the find method to lookup by external source id
                    FileLog.Debug("Searching themoviedb.org for all objects with TVDb ID '{0}'", searchItem.TVDb);

                    var findResults = TMDbAPI.TMDbFind(searchItem.TVDb, TMDbAPI.ExternalSource.tvdb_id);
                    if (findResults == null || findResults.Shows == null || findResults.Shows.Count == 0)
                    {
                        FileLog.Warning("Not enough information to search for trailers from themoviedb.org, no matches found using TVDb ID");
                        return listItems;
                    }

                    // there should only be one
                    searchTerm = findResults.Shows.First().Id.ToString();

                    // cache id so we can use it again
                    PluginSettings.TVDbIds.Add(new PluginSettings.ExternalID { ExternalId = searchItem.TVDb, TmdbId = findResults.Shows.First().Id });
                }
                else
                {
                    FileLog.Debug("Found cached TMDb ID '{0}' for TVDb External ID: '{1}'", externalId.TmdbId.ToString(), searchItem.TVDb);
                    searchTerm = externalId.TmdbId.ToString();
                }
            }
            else if (!string.IsNullOrEmpty(searchItem.IMDb))
            {
                // check if external id is cached
                var externalId = PluginSettings.IMDbIds.FirstOrDefault(t => t.ExternalId == searchItem.IMDb);
                if (externalId == null)
                {
                    FileLog.Debug("Searching themoviedb.org for all objects with IMDb ID '{0}'", searchItem.IMDb);

                    var findResults = TMDbAPI.TMDbFind(searchItem.IMDb, TMDbAPI.ExternalSource.imdb_id);
                    if (findResults == null || findResults.Shows == null || findResults.Shows.Count == 0)
                    {
                        FileLog.Warning("Not enough information to search for trailers from themoviedb.org, no matches found using IMDb ID");
                        return listItems;
                    }

                    // there should only be one
                    searchTerm = findResults.Shows.First().Id.ToString();

                    // cache id so we can use it again
                    PluginSettings.IMDbIds.Add(new PluginSettings.ExternalID { ExternalId = searchItem.IMDb, TmdbId = findResults.Shows.First().Id });
                }
                else
                {
                    FileLog.Debug("Found cached TMDb ID '{0}' for IMDb External ID: '{1}'", externalId.TmdbId.ToString(), searchItem.IMDb);
                    searchTerm = externalId.TmdbId.ToString();
                }
            }
            else if (!string.IsNullOrEmpty(searchItem.TVRage))
            {
                // check if external id is cached
                var externalId = PluginSettings.TVRageIds.FirstOrDefault(t => t.ExternalId == searchItem.TVRage);
                if (externalId == null)
                {
                    FileLog.Debug("Searching themoviedb.org for all objects with TVRage ID '{0}'", searchItem.TVRage);

                    var findResults = TMDbAPI.TMDbFind(searchItem.TVRage, TMDbAPI.ExternalSource.tvrage_id);
                    if (findResults == null || findResults.Shows == null || findResults.Shows.Count == 0)
                    {
                        FileLog.Warning("Not enough information to search for trailers from themoviedb.org, no matches found using TVRage ID");
                        return listItems;
                    }

                    // there should only be one
                    searchTerm = findResults.Shows.First().Id.ToString();

                    // cache id so we can use it again
                    PluginSettings.TVRageIds.Add(new PluginSettings.ExternalID { ExternalId = searchItem.TVRage, TmdbId = findResults.Shows.First().Id });
                }
                else
                {
                    FileLog.Debug("Found cached TMDb ID '{0}' for TVRage External ID: '{1}'", externalId.TmdbId.ToString(), searchItem.TVRage);
                    searchTerm = externalId.TmdbId.ToString();
                }
            }
            else if (!string.IsNullOrEmpty(searchItem.Title))
            {
                // we do the best we can with out any proper show id's
                FileLog.Debug("Searching themoviedb.org for show: Title: '{0}', FirstAired: '{1}'", searchItem.Title, searchItem.AirDate ?? "<empty>");

                var searchResults = TMDbAPI.SearchShows(searchItem.Title, language: "en", firstAirDate: string.IsNullOrEmpty(searchItem.AirDate) ? null : searchItem.AirDate);
                if (searchResults == null || searchResults.TotalResults == 0)
                {
                    FileLog.Warning("No shows found, skipping search from the themoviedb.org.");
                    return listItems;
                }
                else
                {
                    foreach (var show in searchResults.Results)
                    {
                        FileLog.Debug("Found show: Name: '{0}', Original Name: '{1}', Air Date: '{2}', TMDb: '{3}', Popularity: '{4}'", show.Name, show.OriginalName, show.FirstAirDate, show.Id, show.Popularity);
                    }
                }

                // get the show id of the first result, this would be the most likely match (based on popularity)
                // we can think about providing a menu of choices as well based on demand
                searchTerm = searchResults.Results.First().Id.ToString();
                searchItem.TMDb = searchTerm;
            }
            else
            {
                FileLog.Warning("Not enough information to search for trailers from themoviedb.org, require IMDb, TVDb, TMDb or TVRage ID or Title+Year.");
                return listItems;
            }

            FileLog.Debug("Searching for tv {0} trailers using search term '{1}' from themoviedb.org...", searchItem.MediaType.ToString().ToLower(), searchTerm );
            TMDb.DataStructures.TMDbTrailers trailers = null;

            // search for correct type
            switch (searchItem.MediaType)
            {
                case MediaItemType.Show:
                    trailers = GetTvShowTrailersFromCache(searchTerm);
                    break;
                case MediaItemType.Season:
                    trailers = GetTvSeasonTrailersFromCache(searchTerm, searchItem.Season);
                    break;
                case MediaItemType.Episode:
                    trailers = GetTvEpisodeTrailersFromCache(searchTerm, searchItem.Season, searchItem.Episode);
                    break;
            }

            if (trailers == null || trailers.Results == null)
            {
                FileLog.Error("Error getting trailers from themoviedb.org.");
                return listItems;
            }

            foreach (var trailer in trailers.Results)
            {
                var listItem = new GUITrailerListItem();

                string itemName = string.IsNullOrEmpty(trailer.Type) || trailer.Name.ToLowerInvariant().Contains(trailer.Type.ToLowerInvariant()) ? trailer.Name : string.Format("{0} - {1}", trailer.Name, trailer.Type);
                itemName = string.IsNullOrEmpty(trailer.Size) || itemName.ToLowerInvariant().Contains(trailer.Size.ToLowerInvariant()) ? itemName : string.Format("{0} ({1})", itemName, trailer.Size);
                if (PluginSettings.PreferredLanguage != "en")
                {
                    itemName = string.Format("{0} [{1}]", itemName, trailer.LanguageCode);
                }

                listItem.Label = itemName;
                listItem.Label2 = Localisation.Translation.Online;
                listItem.URL = WebUtils.GetYouTubeURL(trailer.Key);
                listItem.TVTag = trailer;
                listItem.IsOnlineItem = true;
                listItem.CurrentMedia = searchItem;

                listItems.Add(listItem);
            }

            FileLog.Info("Found {0} tv {1} trailer(s) from themoviedb.org", trailers.Results.Count.ToString(), searchItem.MediaType.ToString().ToLower());

            return listItems;
        }
        public List<GUITrailerListItem> Search(MediaItem searchItem)
        {
            var listItems = new List<GUITrailerListItem>();

            // Add all trailer search sites available from OnlineVideos
            // Youtube, iTunes and IMDb Trailers
            var listItem = new GUITrailerListItem();

            if (PluginSettings.OnlineVideosYouTubeEnabled && !string.IsNullOrEmpty(searchItem.Title))
            {
                listItem.Label = Translation.YouTubeTrailers;
                listItem.Label2 = Translation.Search;
                listItem.URL = string.Format("site:YouTube|search:{0}|return:Locked", GetYouTubeSearchString(searchItem));
                listItem.IsSearchItem = true;
                listItem.CurrentMedia = searchItem;
                listItems.Add(listItem);
            }

            // iTunes only supports movies
            if (PluginSettings.OnlineVideosITunesEnabled && !string.IsNullOrEmpty(searchItem.Title) && searchItem.MediaType == MediaItemType.Movie)
            {
                listItem = new GUITrailerListItem();
                listItem.Label = Translation.ITunesTrailers;
                listItem.Label2 = Translation.Search;
                listItem.URL = string.Format("site:iTunes Movie Trailers|search:{0}|return:Locked", searchItem.Title);
                listItem.IsSearchItem = true;
                listItem.CurrentMedia = searchItem;
                listItems.Add(listItem);
            }

            // IMDb only supports movies and shows
            if (PluginSettings.OnlineVideosIMDbEnabled && !string.IsNullOrEmpty(searchItem.Title) && (searchItem.MediaType == MediaItemType.Movie || searchItem.MediaType == MediaItemType.Show))
            {
                listItem = new GUITrailerListItem();
                listItem.Label = Translation.IMDbTrailers;
                listItem.Label2 = Translation.Search;
                listItem.URL = string.Format("site:IMDb Movie Trailers|search:{0}|return:Locked", !string.IsNullOrEmpty(searchItem.IMDb) ? searchItem.IMDb : searchItem.Title);
                listItem.IsSearchItem = true;
                listItem.CurrentMedia = searchItem;
                listItems.Add(listItem);
            }

            if (!string.IsNullOrWhiteSpace(PluginSettings.OnlineVideosSitesToSearch) && !string.IsNullOrEmpty(searchItem.Title))
            {
                string[] sites = PluginSettings.OnlineVideosSitesToSearch.Split('|');
                foreach (string s in sites)
                {
                    string site = s.Trim();
                    if (!string.IsNullOrEmpty(site))
                    {
                        listItem = new GUITrailerListItem();
                        listItem.Label = site;
                        listItem.Label2 = Translation.Search;
                        listItem.URL = string.Format("site:{0}|search:{1}|return:Locked", site, searchItem.Title);
                        listItem.IsSearchItem = true;
                        listItem.CurrentMedia = searchItem;
                        listItems.Add(listItem);
                    }
                }
            }

            return listItems;
        }