public ContentEditorWindowViewModel(Content content) { originalContent = content; controlViewModel = new ContentEditorControlViewModel(content, false); this.ResultsOk = false; this.Content.PropertyChanged += Content_PropertyChanged; }
public ContentEditorWindow(Content content) { InitializeComponent(); ContentEditorWindowViewModel vm = new ContentEditorWindowViewModel(content); vm.ResultsSet += vm_ResultsSet; this.DataContext = vm; }
/// <summary> /// Constructor for file from content folder (movie or tv) /// </summary> /// <param name="path">file's path</param> /// <param name="copy">whether file is allowed to be copied</param> /// <param name="allowDelete">whether file is allowed to be deleted</param> /// <param name="folder">content folder file belongs to</param> public OrgPath(string path, bool copy, bool allowDelete, ContentRootFolder folder, Content content) { this.Path = path; this.Copy = copy; this.AllowDelete = allowDelete; this.RootFolder = folder; this.Content = content; this.SimilarTo = -1; }
public ContentEditorControlViewModel(Content content, bool directEditing) { this.ResultsOk = false; // Edit item directly or through clone if (directEditing) this.Content = content; else // Clone content to allow it to be edited, but cancelled switch (content.ContentType) { case ContentType.Movie: this.Content = new Movie(content as Movie); break; case ContentType.TvShow: this.Content = new TvShow(content as TvShow); break; default: throw new Exception("Unknown content type"); } if (this.Content.Id == Content.UNKNOWN_ID && string.IsNullOrEmpty(this.Content.UserName)) { this.DatabaseStatusVisibility = Visibility.Collapsed; this.DatabaseSearchVisibility = Visibility.Visible; } // Get databases for content type this.Databases = new ObservableCollection<string>(); switch (this.Content.ContentType) { case ContentType.Movie: foreach (MovieDatabaseSelection selection in Enum.GetValues(typeof(MovieDatabaseSelection))) this.Databases.Add(selection.Description()); this.SelectedSearchDatabaseIndex = (int)Settings.General.DefaultMovieDatabase; break; case ContentType.TvShow: foreach (TvDataBaseSelection selection in Enum.GetValues(typeof(TvDataBaseSelection))) this.Databases.Add(selection.Description()); this.SelectedSearchDatabaseIndex = (int)Settings.General.DefaultTvDatabase; break; default: throw new Exception("Unknown content type"); } this.SearchResults = new ObservableCollection<Content>(); this.SearchString = System.IO.Path.GetFileName(content.Path); searchWorker = new BackgroundWorker(); searchWorker.WorkerSupportsCancellation = true; searchWorker.DoWork += searchWorker_DoWork; searchWorker.RunWorkerCompleted += searchWorker_RunWorkerCompleted; searchUpdateTimer = new System.Timers.Timer(500); searchUpdateTimer.Elapsed += searchUpdateTimer_Elapsed; }
public ContentControlViewModel(Content content) { this.Content = content; if (Content is TvShow) { TvShow show = this.Content as TvShow; this.EpisodesModel = new EpisodeCollectionControlViewModel(show.Episodes, show); this.PlayVisibility = Visibility.Collapsed; } else this.PlayVisibility = Visibility.Visible; }
/// <summary> /// Check if a root folder contains a specific content instance. Called /// recursively on child root folders. /// </summary> /// <param name="content">The movie to check for</param> /// <returns>Whether the movie is contained in the folder</returns> public bool ContainsContent(Content content, bool recursive) { // Check if movie content folder matches if (content.RootFolder == this.FullPath) return true; else if (recursive) // Recursion on sub-folders foreach (ContentRootFolder subFolder in this.ChildFolders) if (subFolder.ContainsContent(content, recursive)) return true; // No match return false; }
/// <summary> /// Puts a single content item through filtering /// </summary> /// <param name="content">Content to filter</param> /// <param name="genre">Genre content must belong to</param> /// <param name="yearFilter">Enable for year filter</param> /// <param name="minYear">Minimum for year filter</param> /// <param name="maxYear">Maximum for year filter</param> /// <param name="nameFilter">String that must be contained in content name - empty string disables filter</param> /// <returns></returns> public bool ApplyContentFilter(Content content, bool genreEnable, GenreCollection genre, bool yearFilter, int minYear, int maxYear, string nameFilter) { // Apply genre filter bool genreMatch = !genreEnable; if (content.DatabaseGenres != null && !genreMatch) foreach (string contentGenre in content.DatabaseGenres) if (genre.Contains(contentGenre)) { genreMatch = true; break; } // Apply year filter bool yearMatch = !yearFilter || (content.DatabaseYear >= minYear && content.DatabaseYear <= maxYear); // Apply text filter bool nameMatch = string.IsNullOrEmpty(nameFilter) || content.DatabaseName.ToLower().Contains(nameFilter.ToLower()); bool test = genreMatch && yearMatch && nameMatch; if (!test) test = true; // Check if movie is in the folder return genreMatch && yearMatch && nameMatch; }
/// <summary> /// Copies properties from another instance into this instance. /// </summary> /// <param name="content">Instance to copy properties from</param> /// <param name="replacePath">Whether path related properties should be cloned or not</param> /// <param name="handleEmptyPath">Whether to build path if one being cloned is empty</param> public override void CloneAndHandlePath(Content content, bool replacePath, bool handleEmptyPath = true) { if (!(content is TvShow)) throw new Exception("Content must be TvShow"); TvShow show = content as TvShow; bool updateRequired = show.Id != this.Id; base.CloneAndHandlePath(show, replacePath, handleEmptyPath); this.IncludeInSchedule = show.IncludeInSchedule; this.DoMissingCheck = show.DoMissingCheck; this.DvdEpisodeOrder = show.DvdEpisodeOrder; if (updateRequired) this.UpdateInfoFromDatabase(); // TODO: this is a hack App.Current.Dispatcher.BeginInvoke((Action)delegate { this.Episodes.Clear(); foreach (TvEpisode episode in show.Episodes) { TvEpisode copyEp = new TvEpisode(episode); this.Episodes.Add(copyEp); copyEp.Show = this; } }); this.AlternativeNameMatches = new ObservableCollection<string>(); foreach (string altName in show.AlternativeNameMatches) this.AlternativeNameMatches.Add(altName); }
/// <summary> /// Performs update of content information from database. Should be overriden! /// </summary> /// <param name="show">Show instance to update</param> /// <returns>Updated show instance</returns> protected virtual bool DoUpdate(string mirror, Content content) { throw new NotImplementedException(); }
/// <summary> /// Compares 2 movie instances based on their Path property. /// </summary> /// <param name="x">The first movie.</param> /// <param name="y">The second movie.</param> /// <returns>The comparison results </returns> public static int CompareByPath(Content x, Content y) { int sortResult; if (x == null) { if (y == null) sortResult = 0; else sortResult = -1; } else { if (y == null) sortResult = 1; else sortResult = x.Path.CompareTo(y.Path); } return SetSort(sortResult); }
/// <summary> /// Gets TV folder that is set as default /// </summary> /// <returns></returns> public static bool GetTvFolderForContent(Content content, out ContentRootFolder rootFolder) { rootFolder = TvFolders.GetFolderForContent(content); return rootFolder != null; }
/// <summary> /// Match a folder path to content in database /// </summary> /// <param name="rootFolder">Root folder content will belong to</param> /// <param name="path">Current path of content</param> /// <returns>Content from database that was matched, null if no match</returns> protected bool PathMatch(string rootFolder, string path, bool threaded, bool fast, out Content match, Content knownContent) { // Get folder name from full path string[] dirs = path.Split('\\'); string endDir = dirs[dirs.Length - 1]; // Do match return ContentMatch(endDir, rootFolder, path, fast, threaded, out match, knownContent); }
/// <summary> /// Constructor for creating instance from base class /// </summary> /// <param name="content"></param> public Movie(Content content) : this() { base.CloneAndHandlePath(content, true); }
public bool Match(Content content) { string prop; switch (this.Property) { case ContentRootFolderMatchRuleProperty.Name: prop = content.DisplayName; break; case ContentRootFolderMatchRuleProperty.Genre: if (content.DisplayGenres.Count == 0) return false; prop = content.DisplayGenres[0]; break; case ContentRootFolderMatchRuleProperty.Year: prop = content.DisplayYear.ToString(); break; default: throw new Exception("Unknown match rule property."); } string propLower = prop.ToLower(); string valueLower = this.Value.ToLower(); switch (this.Type) { case ContentRootFolderMatchRuleType.Equals: return propLower == valueLower; case ContentRootFolderMatchRuleType.Contains: return propLower.Contains(valueLower); case ContentRootFolderMatchRuleType.StartsWith: return propLower.StartsWith(valueLower); case ContentRootFolderMatchRuleType.EndsWith: return propLower.EndsWith(valueLower); case ContentRootFolderMatchRuleType.RegularExpression: Regex re = new Regex(this.Value, RegexOptions.IgnoreCase); return re.IsMatch(prop); case ContentRootFolderMatchRuleType.Between: Regex yearsRegex = new Regex(@"^(\d{4}).*(\d{4})$"); Match yearMatch = yearsRegex.Match(this.Value); if (yearMatch.Success) { int year1 = 0, year2 = 0; int.TryParse(yearMatch.Groups[1].Value, out year1); int.TryParse(yearMatch.Groups[1].Value, out year2); int minYear = Math.Min(year1, year2); int maxYear = Math.Min(year1, year2); return content.DisplayYear >= minYear && content.DisplayYear <= maxYear; } return false; default: throw new Exception("Unknown match rule criteria."); } }
/// <summary> /// Constructor for cloning instance /// </summary> /// <param name="content">Instance to clone</param> protected Content(Content content) : this() { CloneAndHandlePath(content, true); }
/// <summary> /// Copies properties from another instance into this instance. /// </summary> /// <param name="content">Instance to copy properties from</param> /// <param name="replacePath">Whether path related properties should be cloned or not</param> /// <param name="handleEmptyPath">Whether to build path if one being cloned is empty</param> public virtual void CloneAndHandlePath(Content content, bool replacePath, bool handleEmptyPath = true) { this.ContentType = content.ContentType; this.UserName = content.UserName; this.UseDatabaseName = content.UseDatabaseName; this.DatabaseName = content.DatabaseName; this.DatabaseSelection = content.DatabaseSelection; this.UserYear = content.UserYear; this.UseDatabaseYear = content.UseDatabaseYear; this.DatabaseYear = content.DatabaseYear; this.Overview = content.Overview; this.UseDatabaseGenres = content.UseDatabaseGenres; this.DatabaseGenres = new GenreCollection(content.DatabaseGenres); this.UserGenres = new GenreCollection(content.UserGenres); this.Found = content.Found; if (replacePath) { if (handleEmptyPath) { if (!string.IsNullOrEmpty(content.RootFolder)) this.RootFolder = content.RootFolder; if (!string.IsNullOrEmpty(content.Path) && content.RootFolder != content.Path) this.Path = content.Path; else this.Path = this.BuildFolderPath(); } else { this.RootFolder = content.RootFolder; this.Path = content.Path; } } this.Id = content.Id; this.Watched = content.Watched; this.DoRenaming = content.DoRenaming; this.LastUpdated = content.LastUpdated; }
/// <summary> /// Compares 2 movie instances based on their Year property. /// </summary> /// <param name="x">The first movie.</param> /// <param name="y">The second movie.</param> /// <returns>The comparison results </returns> public static int CompareByYear(Content x, Content y) { int sortResult; if (x == null) { if (y == null) sortResult = 0; else sortResult = 1; } else { if (y == null) sortResult = -1; else sortResult = y.DatabaseYear.CompareTo(x.DatabaseYear); } return SetSort(sortResult); }
/// <summary> /// Updates movie instance properties from database /// </summary> /// <param name="baseMovie">Movie to update</param> /// <returns></returns> protected override bool DoUpdate(string mirror, Content content) { try { // Get movie info from database JsonNode searchNode = GetJsonRequest(mirror, null, "movie/" + content.Id.ToString()); // Parse info into movie instance ParseMovieResult((Movie)content, searchNode.ChildNodes[0]); content.LastUpdated = DateTime.Now; return true; } catch { return false; } }
/// <summary> /// Get search match with lowest modification to search string /// </summary> /// <param name="status">Search status instance</param> /// <param name="lowestModsMatchStrLen">Length of best result's content name</param> /// <param name="results">Best resulting content</param> /// <returns>Whether a valid content match result was found</returns> public bool GetSearchResultWithLowestMods(out ContentSearchMod modsOnResultsSearch, out Content results) { int lowestModsMatchStrLen = 0; modsOnResultsSearch = ContentSearchMod.All; switch (this.ContentType) { case ContentType.Movie: results = new Movie(); break; case ContentType.TvShow: results = new TvShow(); break; default: throw new Exception("Unknown content type"); } // Use match with lowest amount of modification made to search string and longest length (I think this is the most likely to the content we actually want to match to) for (int i = 0; i < this.matches.Length; i++) if (this.matches[i] != null) for (int j = 0; j < this.matches[i].Count; j++) { if (this.matches[i][j].Mods < modsOnResultsSearch || (this.matches[i][j].Mods == modsOnResultsSearch && this.matches[i][j].MatchedString.Length > lowestModsMatchStrLen)) { results = this.matches[i][j].Content; modsOnResultsSearch = this.matches[i][j].Mods; lowestModsMatchStrLen = this.matches[i][j].MatchedString.Length; } } return !string.IsNullOrWhiteSpace(results.DatabaseName); }
/// <summary> /// Constructor for content folder move item. /// </summary> /// <param name="action">action to be performed</param> /// <param name="sourceFile">the source path</param> /// <param name="category">file's category</param> /// <param name="movie">Movie object related to file</param> /// <param name="destination">destination path</param> /// <param name="scanDir">path to content folder of movie</param> public OrgItem(OrgAction action, string sourceFile, Content content, string destination) : this() { this.Progress = 0; this.Action = action; this.SourcePath = sourceFile; if (content is Movie) this.Movie = content as Movie; else this.TvEpisode = new TvEpisode(content as TvShow); this.DestinationPath = destination; this.Category = FileCategory.Folder; this.Enable = false; this.Number = 0; }
/// <summary> /// Gets season/episode information from database /// </summary> /// <param name="show">Show to load episode information into</param> protected override bool DoUpdate(string mirror, Content content) { TvShow show = (TvShow)content; try { // Get show info from database string showInfoUrl = mirror + "/showinfo.php?key=" + this.API_KEY + "&sid=" + show.Id; WebClient webClient = new WebClient(); string showInfo = webClient.DownloadString(showInfoUrl); // Create XML object from results XmlDocument seriesDoc = new XmlDocument(); seriesDoc.InnerXml = showInfo; // Parse show info show.Overview = ParseShowInfo(seriesDoc.DocumentElement).Overview; // Get episode info from database string episodeListUrl = mirror + "/episode_list.php?key=" + this.API_KEY + "&sid=" + show.Id; webClient = new WebClient(); string seriesList = webClient.DownloadString(episodeListUrl); // Create xml object with text from mirrors url seriesDoc = new XmlDocument(); seriesDoc.InnerXml = seriesList; // Get root element and children XmlElement root = seriesDoc.DocumentElement; XmlNodeList nodes = root.ChildNodes; // Go through each node and parse out episodes foreach (XmlNode subNode in nodes) { switch (subNode.Name.ToLower()) { case "episodelist": foreach (XmlNode seasonNode in subNode.ChildNodes) { if (seasonNode.Name.ToLower() == "season") { string seasonNoStr = seasonNode.Attributes["no"].Value; int seasonNo; int.TryParse(seasonNoStr, out seasonNo); foreach (XmlNode epNode in seasonNode.ChildNodes) { TvEpisode ep = new TvEpisode(show); ep.Season = seasonNo; foreach (XmlNode epPropNode in epNode.ChildNodes) switch (epPropNode.Name.ToLower()) { case "seasonnum": // episode number within season int epNum; int.TryParse(epPropNode.InnerText, out epNum); ep.DatabaseNumber = epNum; break; case "airdate": DateTime airDate; DateTime.TryParse(epPropNode.InnerText, out airDate); ep.DatabaseAirDate = airDate; break; case "title": ep.DatabaseName = epPropNode.InnerText; break; case "summary": ep.DatabaseOverview = epPropNode.InnerText.Replace('\n', ' '); break; } ep.InDatabase = true; // If episode already exists just update it, else add it TvEpisode existingMatch; if (show.FindEpisode(ep.Season, ep.DatabaseNumber, true, out existingMatch)) { if (!existingMatch.PreventDatabaseUpdates) { existingMatch.DatabaseName = ep.DatabaseName; existingMatch.DatabaseAirDate = ep.DatabaseAirDate; existingMatch.DatabaseOverview = ep.DatabaseOverview; existingMatch.InDatabase = true; } } else show.Episodes.Add(ep); } } } break; } } return true; } catch { return false; } }
/// <summary> /// Gets TV folder that is set as default /// </summary> /// <returns></returns> public static bool GetTvFolderForContent(Content content, out ContentRootFolder rootFolder) { rootFolder = TvFolders.GetFolderForContent(content); return(rootFolder != null); }
/// <summary> /// Compares 2 movie instances based on their Genre property. /// </summary> /// <param name="x">The first movie.</param> /// <param name="y">The second movie.</param> /// <returns>The comparison results </returns> public static int CompareByGenre(Content x, Content y) { int sortResult; if (x == null) { if (y == null) sortResult = 0; else sortResult = -1; } else { if (y == null) sortResult = 1; else { string genreX = string.Empty, genreY = string.Empty; if (x.DatabaseGenres != null && x.DatabaseGenres.Count > 0) genreX = x.DatabaseGenres[0].ToString(); if (y.DatabaseGenres != null && y.DatabaseGenres.Count > 0) genreY = y.DatabaseGenres[0].ToString(); sortResult = genreX.CompareTo(genreY); } } return SetSort(sortResult); }
/// <summary> /// Search database for content and find a match from results. /// </summary> /// <param name="search">Search string to match content to</param> /// <param name="folderPath">Path of folder containing content</param> /// <param name="rootFolder">Root folder containing content folder</param> /// <param name="year">Year to match to content</param> /// <param name="result">resulting match found from search</param> /// <returns>whether match was successful</returns> private bool DoMatch(string search, string folderPath, string rootFolder, int year, ContentSearchMod baseMods, out List<SearchResult> matches, Content knownContent) { /// Debug notification OnDebugNotificationd("Performing database search for: " + search); // Search for content List<Content> searchResults; if (knownContent == null) searchResults = PerformSearch(search, false); else searchResults = new List<Content>() { knownContent }; // Initialize resutls matches = new List<SearchResult>(); // Go through results if (searchResults != null) foreach (Content searchResult in searchResults) { OnDebugNotificationd("Attempting to match to database entry: " + searchResult); SearchResult result = new SearchResult(); result.Mods = baseMods; // Verify year in result matches year from folder (if any) if (year != -1 && Math.Abs(year - searchResult.DatabaseYear) > 2) continue; // Check if search string match results string string simplifiedSearch = FileHelper.SimplifyFileName(search); string dbContentName = FileHelper.SimplifyFileName(searchResult.DatabaseName); bool theAddedToMatch; bool singleLetterDiff; // Try basic match bool match = FileHelper.CompareStrings(simplifiedSearch, dbContentName, out theAddedToMatch, out singleLetterDiff); result.MatchedString = simplifiedSearch; // Try match with year removed if (!match) { simplifiedSearch = FileHelper.SimplifyFileName(search, true, true, false); dbContentName = FileHelper.SimplifyFileName(searchResult.DatabaseName, true, true, false); match = FileHelper.CompareStrings(simplifiedSearch, dbContentName, out theAddedToMatch, out singleLetterDiff); result.MatchedString = simplifiedSearch; } // Try match with country removed if (!match) { simplifiedSearch = FileHelper.SimplifyFileName(search, true, true, true); dbContentName = FileHelper.SimplifyFileName(searchResult.DatabaseName, true, true, true); match = FileHelper.CompareStrings(simplifiedSearch, dbContentName, out theAddedToMatch, out singleLetterDiff); if (match) result.Mods |= ContentSearchMod.WordsRemoved; result.MatchedString = simplifiedSearch; } // Try match with spaces removed if (!match) { string dirNoSpc = simplifiedSearch.Replace(" ", ""); string nameNoSpc = dbContentName.Replace(" ", ""); match = FileHelper.CompareStrings(dirNoSpc, nameNoSpc, out theAddedToMatch, out singleLetterDiff); result.MatchedString = simplifiedSearch; if (match) result.Mods |= ContentSearchMod.SpaceRemoved; } // Try match with year added to content name if (!match) { simplifiedSearch = FileHelper.SimplifyFileName(search); dbContentName = FileHelper.SimplifyFileName(searchResult.DatabaseName + " " + searchResult.DatabaseYear.ToString()); match = FileHelper.CompareStrings(simplifiedSearch, dbContentName, out theAddedToMatch, out singleLetterDiff); result.MatchedString = simplifiedSearch; } if (theAddedToMatch) result.Mods |= ContentSearchMod.TheAdded; if (singleLetterDiff) result.Mods |= ContentSearchMod.SingleLetterAdded; // Match notification if (match) OnDebugNotificationd("Matched with following mods: " + result.Mods); // No match, next result! if (!match) continue; // Set results folder/path result.Content = searchResult; result.Content.RootFolder = rootFolder; if (string.IsNullOrEmpty(folderPath)) result.Content.Path = result.Content.BuildFolderPath(); else result.Content.Path = folderPath; // Save results matches.Add(result); } return matches.Count > 0; }
/// <summary> /// Constructor for creating instance from inherited class /// </summary> /// <param name="content"></param> public TvShow(Content content) : this() { base.CloneAndHandlePath(content, true); }
/// <summary> /// Attempts to match string to content from the online database. /// </summary> /// <param name="search">Search string to match against</param> /// <param name="rootFolder">The root folder the content will belong to</param> /// <param name="folderPath">Folder path where the content should be moved to</param> /// <returns>Match content item, null if no match</returns> protected bool ContentMatch(string search, string rootFolder, string folderPath, bool fast, bool threaded, out Content match, Content knownContent) { // Create empty content Content emptyContent; switch (this.ContentType) { case ContentType.Movie: emptyContent = new Movie(); break; case ContentType.TvShow: emptyContent = new TvShow(); break; default: throw new Exception("Unknown content type"); } emptyContent.Path = folderPath; emptyContent.RootFolder = rootFolder; emptyContent.Found = true; // Check for empty search condition if (string.IsNullOrEmpty(search)) { match = emptyContent; return false; } // Get year from search string int dirYear = FileHelper.GetYear(search); // Get list of simplified strings List<FileHelper.SimplifyStringResults> searches = new List<FileHelper.SimplifyStringResults>(); // Get list of search bases List<string> searchBases = GetModifiedSearches(search); // Fast search: use first search base only if (fast) { FileHelper.SimplifyStringResults result = FileHelper.BuildSimplifyResults(searchBases[0], false, false, FileHelper.OptionalSimplifyRemoves.YearAndFollowing, true, false, true, false); searches.Add(result); } // Full search: Go through each search base and get simplified search options else foreach (string searchBase in searchBases) { // Get results from current base List<FileHelper.SimplifyStringResults> currSearches = FileHelper.SimplifyString(searchBase); currSearches.Add(new FileHelper.SimplifyStringResults(searchBase, new Dictionary<FileWordType, List<string>>(), ContentSearchMod.None)); // Add each result to full list of searches foreach (FileHelper.SimplifyStringResults results in currSearches) { // Check if search already exist bool exists = false; foreach (FileHelper.SimplifyStringResults s in searches) if (s.SimplifiedString == results.SimplifiedString) { exists = true; break; } // If doesn't exist add it to searches if (!exists && !string.IsNullOrWhiteSpace(results.SimplifiedString)) searches.Add(results); } } searches.Sort(); // Create new status int currSeachCnt; MatchStatus status; lock (searchLock) { currSeachCnt = ++searchCount; status = new MatchStatus(searches.Count, this.ContentType); searchStatus.Add(currSeachCnt, status); } ContentSearchMod lowMods; Content lowestModsMatch; // Add thread to pool for each search that need to be performed int searchNum = 0; while (searchNum < searches.Count) { // Check for any search results so far if (status.GetSearchResultWithLowestMods(out lowMods, out lowestModsMatch)) { // If search results have no mods or just year removed use them as final results if (lowMods == ContentSearchMod.None || lowMods == ContentSearchMod.YearRemoved) { match = lowestModsMatch; return true; } } // Limit number of search threads created if (status.NumStarted - status.NumCompleted >= Settings.General.NumSimultaneousSearches) { Thread.Sleep(100); continue; } // Build search arguments object[] args = { currSeachCnt, searchNum, searches[searchNum].SimplifiedString, folderPath, rootFolder, dirYear, searches[searchNum].Modifications, knownContent }; // Threaded: add a search to thread pool if (threaded) { ThreadPool.QueueUserWorkItem(new WaitCallback(SearchThread), args); lock (searchLock) status.SetSearchStarted(searchNum); } // Synchronized: call search method else SearchThread(args); searchNum++; } // Wait for all search to complete while (status.NumCompleted < searches.Count) { // Check for any search results so far if (status.GetSearchResultWithLowestMods(out lowMods, out lowestModsMatch)) { // If search results have no mods or just year removed use them as final results if (lowMods == ContentSearchMod.None || lowMods == ContentSearchMod.YearRemoved) { match = lowestModsMatch; return true; } } Thread.Sleep(100); } // Clear status lock (searchLock) searchStatus.Remove(currSeachCnt); // Return result with lowest mods to search string if (status.GetSearchResultWithLowestMods(out lowMods, out lowestModsMatch)) { match = lowestModsMatch; return true; } else { match = emptyContent; return false; } }
public new void Clone(Content content) { CloneAndHandlePath(content, true, false); }
/// <summary> /// Updates show's season/episode information from database. Use for newly /// added shows only, as it will replace all episode information in show. /// </summary> /// <param name="show">Show to load episode information into</param> protected override bool DoUpdate(string mirror, Content content) { TvShow show = (TvShow)content; bool success = true; string tempPath = string.Empty; try { // Download episodes XML string string showUrl = mirror + "/api/" + API_KEY + "/series/" + show.Id + "/all/en.zip"; string basePath = Organization.GetBasePath(true); Guid guid = Guid.NewGuid(); tempPath = Path.Combine(basePath, guid.ToString()); Directory.CreateDirectory(tempPath); string zipPath = Path.Combine(tempPath, "data" + ".zip"); string extractPath = Path.Combine(tempPath, "en.xml"); WebClient webClient = new WebClient(); webClient.DownloadFile(showUrl, zipPath); ZipFile zip = ZipFile.Read(zipPath); foreach (ZipEntry entry in zip.Entries) if (entry.FileName == "en.xml") { entry.Extract(tempPath, ExtractExistingFileAction.OverwriteSilently); break; } zip.Dispose(); XmlDocument showDoc = new XmlDocument(); showDoc.Load(extractPath); // Get root element and children XmlElement root = showDoc.DocumentElement; XmlNodeList rootNodes = root.ChildNodes; // Go through each node and get info for each episode foreach (XmlNode node in rootNodes) { if (node.Name == "Series") { XmlNodeList serNodes = node.ChildNodes; foreach (XmlNode subNode in serNodes) { switch (subNode.Name) { case "Genre": string[] genres = subNode.InnerText.Split('|'); foreach(string genre in genres) if(!string.IsNullOrWhiteSpace(genre) && !show.DatabaseGenres.Contains(genre)) show.DatabaseGenres.Add(genre); break; } } } else if (node.Name == "Episode") { TvEpisode ep = new TvEpisode(show); int season = -1; XmlNodeList subNodes = node.ChildNodes; foreach (XmlNode subNode in subNodes) { switch (subNode.Name) { case "EpisodeNumber": int epNumber = 0; int.TryParse(subNode.InnerText, out epNumber); ep.DatabaseNumber = epNumber; break; case "DVD_episodenumber": double dvdNumber = -1; if (double.TryParse(subNode.InnerText, out dvdNumber)) ep.DatabaseDvdNumber = (int)dvdNumber; break; case "EpisodeName": ep.DatabaseName = subNode.InnerText; break; case "SeasonNumber": season = Convert.ToInt32(subNode.InnerText); ep.Season = season; break; case "FirstAired": DateTime airData; DateTime.TryParse(subNode.InnerText, out airData); ep.DatabaseAirDate = airData; break; case "Overview": ep.DatabaseOverview = subNode.InnerText; break; } } ep.InDatabase = true; if (ep.DisplayNumber > -1 && season > -1) { // If episode already exists just update it, else add it TvEpisode existingMatch; if (show.FindEpisode(ep.Season, ep.DatabaseNumber, true, out existingMatch)) { existingMatch.DatabaseName = ep.DatabaseName; existingMatch.DatabaseAirDate = ep.DatabaseAirDate; existingMatch.DatabaseOverview = ep.DatabaseOverview; existingMatch.InDatabase = true; } else show.Episodes.Add(ep); } } } showDoc = null; } catch(Exception e) { Console.WriteLine("Exception caught on TvDb update: " + e.ToString()); success = false; } finally { if (Directory.Exists(tempPath)) Directory.Delete(tempPath, true); } return success; }
public virtual bool Update(Content content) { string mirror; if (!GetMirror(this.UpdateMirrorType, out mirror)) return false; // Tries up to 5 times - database can fail randomly for (int j = 0; j < 5; j++) { try { DoUpdate(mirror, content); return true; } catch { } } return false; }