/// <summary> /// Search through all sub-folders and attempt to assign each one to content. /// </summary> /// <param name="fastUpdate">Whether update is fast, skips detailed updating(e.g. episodes for shows)</param> /// <param name="idsToUpdate">List of dtabase IDs that need updating</param> /// <param name="cancel">Cancelation flag</param> /// <param name="serverTime">Time on online database server</param> /// <returns>Whether update was completed without cancelation</returns> public bool UpdateContent(bool fastUpdate, ref bool cancel) { updateCancelled = false; // Update progress string progressMsg = "Update of '" + this.FullPath + "' started - Building threads"; OnUpdateProgressChange(this, false, 0, progressMsg); // Initialize processing - First pass OrgProcessing firstPass = new OrgProcessing(UpdateProcess); updateNumber = firstPass.ProcessNumber; // Run 1st pass (build of sub-dirs is recursive, so all child root folder sub-dirs will be included) firstPass.Run(BuildSubDirectories(this.ContentType), ref cancel, true, Settings.General.NumProcessingThreads); updateCancelled = cancel; // Initialize processing - Second pass OrgProcessing secondPass = new OrgProcessing(UpdateProcess); updateNumber = secondPass.ProcessNumber; // Run 2nd pass (build of sub-dirs is recursive, so all child root folder sub-dirs will be included) secondPass.Run(BuildSubDirectories(this.ContentType), ref cancel, false, Settings.General.NumProcessingThreads); updateCancelled = cancel; // Get content collection to add content to ContentCollection content = GetContentCollection(); // Remove shows that no longer exists if (!cancel) { content.RemoveMissing(); } // Save changes //content.Sort(); content.Save(); // Set progress to completed progressMsg = "Update of '" + this.FullPath + "' complete!"; OnUpdateProgressChange(this, false, 100, progressMsg); OnUpdateProgressComplete(this); // Return whether update was completed without cancelation return(!cancel); }
/// <summary> /// Builds a list of content matching filter that is contained within a root folder /// </summary> /// <param name="genre">Filter for genre type - use "All" to disable filter</param> /// <param name="contents">List to add content to</param> /// <param name="yearFilter">Enables year filtering</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> public void GetContent(bool recursive, bool genreEnable, GenreCollection genre, List <Content> contents, bool yearFilter, int minYear, int maxYear, string nameFilter) { // Go through all movies ContentCollection contentCollection = GetContentCollection(); lock (contentCollection.ContentLock) { //Console.WriteLine(contentCollection.ToString() + " lock get"); foreach (Content content in contentCollection) { // Apply genre filter bool genreMatch = false; 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()); // Check if movie is in the folder if (ContainsContent(content, recursive) && ApplyContentFilter(content, genreEnable, genre, yearFilter, minYear, maxYear, nameFilter)) { contents.Add(content); } } } //Console.WriteLine(contentCollection.ToString() + " release get"); }
/// <summary> /// Load collection from saved XML file /// </summary> public void Load(bool doUpdating) { XmlTextReader reader = null; XmlDocument xmlDoc = new XmlDocument(); try { string path = Path.Combine(Organization.GetBasePath(false), XML_ROOT + ".xml"); if (File.Exists(path)) { // Use dummy collection to load into so that loading doesn't hog use of object ContentCollection loadContent = new ContentCollection(this.ContentType, "Loading Shows"); lock (XmlLock) { // Load XML reader = new XmlTextReader(path); xmlDoc.Load(reader); // Extract data XmlNodeList contentNodes = xmlDoc.DocumentElement.ChildNodes; for (int i = 0; i < contentNodes.Count; i++) { // Update loading progress OnLoadProgressChange((int)(((double)i / contentNodes.Count) * 100)); // All elements will be content items or last update time if (contentNodes[i].Name == "LastUpdate") { loadContent.LastUpdate = contentNodes[i].InnerText; } else { // Load content from element based on type switch (this.ContentType) { case ContentType.TvShow: TvShow show = new TvShow(); if (show.Load(contentNodes[i])) { bool rootFolderExists = false; foreach (ContentRootFolder folder in Settings.GetAllRootFolders(this.ContentType, true)) { if (folder.FullPath == show.RootFolder) { rootFolderExists = true; } } if (!rootFolderExists || !Directory.Exists(show.Path)) { continue; } loadContent.Add(show); if (doUpdating) { show.UpdateMissing(); } } break; case ContentType.Movie: Movie movie = new Movie(); if (movie.Load(contentNodes[i])) { loadContent.Add(movie); } break; default: throw new Exception("Unknown content type"); } } } } // Update progress OnLoadProgressChange(100); this.LastUpdate = loadContent.LastUpdate; this.Clear(); AddMultiple(loadContent); } } catch (Exception e) { MessageBox.Show(e.ToString(), "Error loading " + this.ContentType + "s from saved data!"); } finally { if (reader != null) { reader.Close(); } } // Start updating of TV episode in scan dirs. if (this.ContentType == ContentType.TvShow && doUpdating) { TvItemInScanDirHelper.DoUpdate(false); TvItemInScanDirHelper.StartUpdateTimer(); } // Trigger load complete event OnLoadComplete(); }
/// <summary> /// Update processing method (thread) for single content folder in root. /// </summary> /// <param name="orgPath">Organization path instance to be processed</param> /// <param name="pathNum">The path's number out of total being processed</param> /// <param name="totalPaths">Total number of paths being processed</param> /// <param name="processNumber">The identifier for the OrgProcessing instance</param> /// <param name="numItemsProcessed">Number of paths that have been processed - used for progress updates</param> /// <param name="numItemsStarted">Number of paths that have had been added to thread pool for processing</param> /// <param name="processSpecificArgs">Arguments specific to this process</param> private void UpdateProcess(OrgPath orgPath, int pathNum, int totalPaths, int processNumber, ref int numItemsProcessed, ref int numItemsStarted, object processSpecificArgs) { // Check for cancellation - this method is called from thread pool, so cancellation could have occured by the time this is run if (updateCancelled || this.updateNumber != processNumber) { return; } // First pass run does quick folder update by skipping online database searching bool firstPass = (bool)processSpecificArgs; string passString = firstPass ? " (First Pass)" : " (Second Pass)"; // Set processing messge string progressMsg = "Updating of '" + orgPath.RootFolder.FullPath + "'" + passString + " - '" + Path.GetFileName(orgPath.Path) + "' started"; OnUpdateProgressChange(this, false, CalcProgress(numItemsProcessed, numItemsStarted, totalPaths), progressMsg); // Get content collection to add content to ContentCollection content = GetContentCollection(); // Check if folder already has a match to existing content bool contentExists = false; bool contentComplete = false; Content newContent = null; int index = 0; for (int j = 0; j < content.Count; j++) { if (Path.Equals(orgPath.Path, content[j].Path)) { contentExists = true; content[j].Found = true; if (!string.IsNullOrEmpty(content[j].DatabaseName)) { contentComplete = true; } newContent = content[j]; index = j; break; } } // Set completed progess message progressMsg = "Updating of '" + orgPath.RootFolder.FullPath + "'" + passString + " - '" + Path.GetFileName(orgPath.Path) + "' complete"; // Check if content found if (contentExists && contentComplete) { // Check if content needs updating if ((DateTime.Now - newContent.LastUpdated).TotalDays > 7 && this.ContentType == ContentType.TvShow) { newContent.UpdateInfoFromDatabase(); } // Update progress if (this.updateNumber == processNumber) { OnUpdateProgressChange(this, false, CalcProgress(numItemsProcessed, numItemsStarted, totalPaths), progressMsg); } return; } // Folder wasn't matched to an existing content instance, try tmatch folder to content from online database Content match; bool matchSucess; switch (this.ContentType) { case ContentType.TvShow: TvShow showMatch; matchSucess = SearchHelper.TvShowSearch.PathMatch(orgPath.RootFolder.FullPath, orgPath.Path, firstPass, true, out showMatch); match = showMatch; break; case ContentType.Movie: Movie movieMatch; matchSucess = SearchHelper.MovieSearch.PathMatch(orgPath.RootFolder.FullPath, orgPath.Path, firstPass, true, out movieMatch); match = movieMatch; break; default: throw new Exception("unknown content type"); } // Check that current process hasn't been replaced - search can be slow, so update may have been cancelled by the time it gets here if (updateCancelled || this.updateNumber != processNumber) { return; } // Folder already existed, but wasn't previously match to valid content if (contentExists && matchSucess) { switch (this.ContentType) { case ContentType.TvShow: ((TvShow)newContent).CloneAndHandlePath((TvShow)match, true); ((TvShow)newContent).UpdateMissing(); break; case ContentType.Movie: ((Movie)newContent).CloneAndHandlePath((Movie)match, true); break; default: throw new Exception("unknown content type"); } newContent.LastUpdated = DateTime.Now; } else if (matchSucess) { newContent = match; } else { switch (this.ContentType) { case ContentType.TvShow: newContent = new TvShow(string.Empty, 0, 0, orgPath.Path, orgPath.RootFolder.FullPath); break; case ContentType.Movie: newContent = new Movie(string.Empty, 0, 0, orgPath.Path, orgPath.RootFolder.FullPath); break; default: throw new Exception("unknown content type"); } } // Set found flag newContent.Found = true; // Add content to list if new if (!contentExists) { content.Add(newContent); } // Update progress OnUpdateProgressChange(this, true, CalcProgress(numItemsProcessed, numItemsStarted, totalPaths), progressMsg); }