private async Task <OrganizeSummary> OrganizeAsync(CopyItems items)
        {
            if (items == null)
            {
                throw new ArgumentNullException(nameof(items));
            }

            OnProgress(this, PARSE_PROGRESS_FACTOR + 0.1, "Prepare destination");

            try
            {
                OrganizeSummary summary = new OrganizeSummary();

                await Task.Run(() => OrganizationThread(items, summary));

                return(summary);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#else
                return(null);
#endif
            }
            finally
            {
                OnProgress(this, 1.0, "Organization complete");
            }
        }
        public async Task OrganizeAsync()
        {
            if (workerRunning)
            {
                throw new InvalidOperationException("Cannot start parsing: worker currently running");
            }
            workerRunning = true;
            workerAborted = false;

            try
            {
                dynamic temp = await ParseAsync();

                OnParseDone(this, temp.Summary);

                if (workerAborted)
                {
                    return;
                }

                OrganizeSummary organizeSummary = await OrganizeAsync(temp.Items);

                OnOrganizeDone(this, organizeSummary);
            }
            finally
            {
                Cleanup();

                workerRunning = false;
            }
        }
        private void OrganizationThread(CopyItems items, OrganizeSummary summary)
        {
            PrepareDestinationPath(items);

            int itemCount = items.Count;

            for (int i = 0; i < itemCount; i++)
            {
                if (workerAborted)
                {
                    break;
                }

                float progress = (float)(i) / (float)itemCount;
                if ((int)(progress * 10) % 2 == 0)
                {
                    OnProgress(this, PARSE_PROGRESS_FACTOR + 0.1 + (progress * (1.0 - PARSE_PROGRESS_FACTOR - 0.1)), $"Organizing {i + 1} of {itemCount}");
                }

                CopySourceToDestination(items[i], summary);
            }
        }
        private void CopySourceToDestination(CopyItem item, OrganizeSummary summary)
        {
            string destinationDirectory = Path.GetDirectoryName(item.destinationPath);

            if (!Directory.Exists(destinationDirectory))
            {
                try
                {
                    Directory.CreateDirectory(destinationDirectory);
                }
                catch (Exception ex)
                {
                    if (ExceptionHandling == ExceptionHandling.Throw)
                    {
                        throw new MediaOrganizerException($"Failed to create directory: {destinationDirectory}", ex);
                    }

                    Trace.WriteLine($"[{nameof(MediaOrganizer)}] Ignored exception: {ex.Message}");
                    return;
                }
            }

            summary.sources.Add(item.sourcePath);
            summary.destinations.Add(item.destinationPath);

            bool   overwrite             = false;
            string targetDestinationPath = item.destinationPath; // Note: path may be altered later on to resolve conflicts
            bool   fileExists            = File.Exists(targetDestinationPath);

            switch (CopyMode)
            {
            case CopyMode.OverwriteExisting:
                overwrite = true;
                if (fileExists)
                {
                    summary.overwritten[item.sourcePath] = targetDestinationPath;
                    Trace.WriteLine($"[{nameof(MediaOrganizer)}] Force overwrite file: {targetDestinationPath}");
                }
                break;

            case CopyMode.KeepExisting:
                if (fileExists)
                {
                    summary.skipped[item.sourcePath] = targetDestinationPath;
                    Trace.WriteLine($"[{nameof(MediaOrganizer)}] Keep existing file: {targetDestinationPath}");
                    return;
                }
                break;

            case CopyMode.KeepUnique:
                FileInfo sourceInfo      = item.sourceInfo;
                FileInfo destinationInfo = new FileInfo(targetDestinationPath);
                if (fileExists)
                {
                    // Potentially slow, therefore previous optimizations
                    if (sourceInfo.AreFilesIdentical(destinationInfo, FileComparator))
                    {
                        summary.duplicates[item.sourcePath] = targetDestinationPath;
                        Trace.WriteLine($"[{nameof(MediaOrganizer)}] Duplicate file ignored: {item.sourcePath} (duplicate of {targetDestinationPath})");
                        return;
                    }
                }

                if (sourceInfo.FileExistsInDirectory(destinationInfo.Directory, FileComparator))
                {
                    summary.duplicates[item.sourcePath] = destinationInfo.Directory.FullName;
                    Trace.WriteLine($"[{nameof(MediaOrganizer)}] Duplicate file ignored: {item.sourcePath} (exists in {destinationInfo.Directory})");
                    return;     // Source file already exists in target directory
                }

                // Find next unused filename
                string originalDestinationPath = targetDestinationPath;
                int    index = 1;
                while (fileExists)
                {
                    targetDestinationPath = destinationInfo.SuffixFileName(index++);
                    fileExists            = File.Exists(targetDestinationPath);
                }
                if (targetDestinationPath != originalDestinationPath)
                {
                    summary.renamed[originalDestinationPath] = targetDestinationPath;
                    Trace.WriteLine($"[{nameof(MediaOrganizer)}] Renamed to prevent conflict: {targetDestinationPath} (original: {originalDestinationPath})");
                }
                break;

            default:
                throw new NotImplementedException($"CopyMode: {CopyMode}");
            }

            try
            {
                File.Copy(item.sourcePath, targetDestinationPath, overwrite);
                summary.modified.Add(targetDestinationPath);
                if (FileVerification != FileComparator.None)
                {
                    if (!item.sourceInfo.AreFilesIdentical(new FileInfo(targetDestinationPath), FileVerification))
                    {
                        throw new MediaOrganizerException("File verification failed. Source: {0}. Destination: {1}", item.sourcePath, targetDestinationPath);
                    }
                }
            }
            catch (Exception ex)
            {
                if (ExceptionHandling == ExceptionHandling.Throw)
                {
                    throw new MediaOrganizerException($"Failed to copy file. Mode: {CopyMode}. Overwrite: {overwrite}. Source: {item.sourcePath}. Destination: {targetDestinationPath}", ex);
                }

                Trace.WriteLine($"[{nameof(MediaOrganizer)}] Ignored exception: {ex.Message}");
            }
        }
Exemple #5
0
        private async void ParseComplete(MediaOrganizer organizer, OrganizeSummary summary)
        {
            if (InvokeRequired)
            {
                Action<MediaOrganizer, OrganizeSummary> action = new Action<MediaOrganizer, OrganizeSummary>(ParseComplete);
                BeginInvoke(action, organizer, summary);
                return;
            }

            if (MessageBox.Show(summary.ToString(), "Continue organization?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
            {
                ProgressEnded();
                return;
            }

            try
            {
                await organizer.OrganizeAsync();
                OrganizeComplete(organizer);
            }
            catch (Exception ex)
            {
                OrganizeException(ex);
            }
        }
Exemple #6
0
        private async Task<List<CopyItem>> ParseItemsAsync(string sourcePath, string destinationPath, OrganizeSummary summary)
        {
            List<string> ignore = new List<string>();
            if (IgnorePaths != null)
                ignore.AddRange(IgnorePaths);
            if (!sourcePath.DirectoryAreSame(destinationPath))
                ignore.Add(destinationPath);

            IEnumerable<MetaData> data;
            try
            {
                MetaParserConfig config = new MetaParserConfig() { Recursive = Recursive, IgnorePaths = ignore };
                data = await MetaParser.ParseAsync(sourcePath, config);
            }
            catch (MetaParseException ex)
            {
                throw new MediaOrganizerException("Failed to parse meta data", ex);
            }

            PatternPathParser parser = new PatternPathParser(Locale);
            parser.Preload(data);

            HashSet<string> files = new HashSet<string>();
            HashSet<string> directories = new HashSet<string>();
            HashSet<string> valid = new HashSet<string>();
            HashSet<string> ignored = new HashSet<string>();
            List<CopyItem> items = new List<CopyItem>();
            foreach (MetaData meta in data)
            {
                if (workerAborted)
                    break;

                string path = meta.Path;

                switch (meta.Type)
                {
                    case MetaType.Directory:
                        directories.Add(path);
                        continue;
                    case MetaType.File:
                        files.Add(path);
                        ignored.Add(path);
                        continue;
                    default:
                        files.Add(path);
                        break;
                }

                CopyItem item = ParseItem(parser, destinationPath, meta);
                items.Add(item);
                valid.Add(path);
            }

            summary.totalDirectories = directories.ToArray();
            summary.totalFiles = files.ToArray();
            summary.parsed = valid.ToArray();
            summary.ignored = ignored.ToArray();

            return items;
        }
Exemple #7
0
        public async Task<OrganizeSummary> ParseAsync()
        {
            if (sourcePath.DirectoryAreSame(destinationPath))
            {
                // TODO: implement
                throw new NotSupportedException("TODO");
            }

            if (workerRunning)
                throw new InvalidOperationException("Cannot start parsing: worker currently running");
            workerRunning = true;
            workerAborted = false;

            OnProgress(this, 0.0, "Parsing source");

            try
            {
                OrganizeSummary summary = new OrganizeSummary();

                copyItems = new CopyItems();
                copyItems.sourcePath = sourcePath;
                copyItems.destinationPath = destinationPath;
                copyItems.items = await ParseItemsAsync(sourcePath, destinationPath, summary);

                return summary;
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#else
                return null;
#endif
            }
            finally
            {
                workerRunning = false;

                OnProgress(this, PARSE_PROGRESS_FACTOR, "Parsing complete");
            }
        }