예제 #1
0
        public async void StartSearch()
        {
            Duplicates.Clear();
            positionList.Clear();
            ElapsedTimer.Reset();
            SearchSW.Reset();
            float positionCounter = 0f;

            for (var i = 0; i < Settings.ThumbnailCount; i++)
            {
                positionCounter += 1.0F / (Settings.ThumbnailCount + 1);
                positionList.Add(positionCounter);
            }
            _isScanning              = true;
            m_pauseTokeSource        = new PauseTokenSource();
            m_cancelationTokenSource = new CancellationTokenSource();

            //get files
            Logger.Instance.Info(Properties.Resources.BuildingFileList);
            await Task.Run(() => InternalBuildFileList());

            FilesEnumerated?.Invoke(this, new EventArgs());
            //start scan
            Logger.Instance.Info(Properties.Resources.StartScan);
            if (!m_cancelationTokenSource.IsCancellationRequested)
            {
                await Task.Run(() => InternalSearch(m_cancelationTokenSource.Token, m_pauseTokeSource));
            }
            ScanDone?.Invoke(this, new EventArgs());
            Logger.Instance.Info(Properties.Resources.ScanDone);
            _isScanning       = false;
            ScanProgressValue = 0;
            DatabaseHelper.SaveDatabase(DatabaseFileList);
        }
예제 #2
0
        private void InternalSearch(CancellationToken cancelToken, PauseTokenSource pauseTokenSource)
        {
            ElapsedTimer.Start();
            SearchSW.Start();
            var duplicateDict = new Dictionary <string, DuplicateItem>();

            try {
                var parallelOpts = new ParallelOptions {
                    MaxDegreeOfParallelism = Environment.ProcessorCount,
                    CancellationToken      = cancelToken
                };

                var reScanList = ScanFileList
                                 .Where(vf => !vf.Flags.Any(EntryFlags.ManuallyExcluded | EntryFlags.AllErrors))
                                 .Where(vf => (vf.mediaInfo == null && !vf.IsImage) || vf.grayBytes == null || vf.grayBytes.Count != Settings.ThumbnailCount)
                                 .ToList();

                InitProgress(reScanList.Count);
                Parallel.For(0, reScanList.Count, parallelOpts, i => {
                    while (pauseTokenSource.IsPaused)
                    {
                        Thread.Sleep(50);
                    }
                    var entry = reScanList[i];

                    if (entry.mediaInfo == null && !entry.IsImage)
                    {
                        var ffProbe = new FFProbeWrapper.FFProbeWrapper();
                        var info    = ffProbe.GetMediaInfo(entry.Path);
                        if (info == null)
                        {
                            entry.Flags.Set(EntryFlags.MetadataError);
                            return;
                        }
                        entry.mediaInfo = info;
                    }

                    if (entry.grayBytes == null)
                    {
                        var(error, grayBytes) = entry.IsImage ? GetImageAsBitmaps(entry, positionList.Count) : GetVideoThumbnailAsBitmaps(entry, positionList);
                        if (error > 0)
                        {
                            entry.Flags.Set(error);
                        }
                        else
                        {
                            entry.grayBytes = grayBytes;
                        }
                    }

                    IncrementProgress(entry.Path);
                });
                SearchSW.Stop();
                Logger.Instance.Info(string.Format(Properties.Resources.ThumbnailsFinished, SearchSW.Elapsed, processedFiles));

                SearchSW.Restart();
                var percentageDifference = 1.0f - Settings.Percent / 100f;
                var dupeScanList         = ScanFileList.Where(vf => !vf.Flags.Any(EntryFlags.AllErrors | EntryFlags.ManuallyExcluded)).ToList();

                InitProgress(dupeScanList.Count);
                Parallel.For(0, dupeScanList.Count, parallelOpts, i => {
                    while (pauseTokenSource.IsPaused)
                    {
                        Thread.Sleep(50);
                    }

                    var baseItem = dupeScanList[i];
                    if (baseItem.grayBytes == null || baseItem.grayBytes.Count == 0)
                    {
                        IncrementProgress(baseItem.Path);
                        return;
                    }

                    for (var n = i + 1; n < dupeScanList.Count; n++)
                    {
                        var compItem = dupeScanList[n];
                        if (baseItem.IsImage && !compItem.IsImage)
                        {
                            continue;
                        }
                        if (compItem.grayBytes == null || compItem.grayBytes.Count == 0)
                        {
                            continue;
                        }
                        if (baseItem.grayBytes.Count != compItem.grayBytes.Count)
                        {
                            continue;
                        }
                        var duplicateCounter = 0;
                        var percent          = new float[baseItem.grayBytes.Count];
                        for (var j = 0; j < baseItem.grayBytes.Count; j++)
                        {
                            Debug.Assert(baseItem.grayBytes[j].Length == compItem.grayBytes[j].Length, "Images must be of same length");
                            percent[j] = ExtensionMethods.PercentageDifference(baseItem.grayBytes[j], compItem.grayBytes[j]);
                            if (percent[j] < percentageDifference)
                            {
                                duplicateCounter++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (duplicateCounter != baseItem.grayBytes.Count)
                        {
                            continue;
                        }

                        var percSame = percent.Average();
                        lock (duplicateDict) {
                            var foundBase = duplicateDict.TryGetValue(baseItem.Path, out var existingBase);
                            var foundComp = duplicateDict.TryGetValue(compItem.Path, out var existingComp);

                            if (foundBase && foundComp)
                            {
                                //this happens with 4+ identical items:
                                //first, 2+ duplicate groups are found independently, they are merged in this branch
                                if (existingBase.GroupId != existingComp.GroupId)
                                {
                                    foreach (var dup in duplicateDict.Values.Where(c => c.GroupId == existingComp.GroupId))
                                    {
                                        dup.GroupId = existingBase.GroupId;
                                    }
                                }
                            }
                            else if (foundBase)
                            {
                                duplicateDict.Add(compItem.Path, new DuplicateItem(compItem, percSame)
                                {
                                    GroupId = existingBase.GroupId
                                });
                            }
                            else if (foundComp)
                            {
                                duplicateDict.Add(baseItem.Path, new DuplicateItem(baseItem, percSame)
                                {
                                    GroupId = existingComp.GroupId
                                });
                            }
                            else
                            {
                                var groupId = Guid.NewGuid();
                                duplicateDict.Add(compItem.Path, new DuplicateItem(compItem, percSame)
                                {
                                    GroupId = groupId
                                });
                                duplicateDict.Add(baseItem.Path, new DuplicateItem(baseItem, percSame)
                                {
                                    GroupId = groupId
                                });
                            }
                        }
                    }
                    IncrementProgress(baseItem.Path);
                });

                SearchSW.Stop();
                Logger.Instance.Info(string.Format(Properties.Resources.DuplicatesCheckFinishedIn, SearchSW.Elapsed));
                Duplicates = new HashSet <DuplicateItem>(duplicateDict.Values);
            }
            catch (OperationCanceledException) {
                Logger.Instance.Info(Properties.Resources.CancellationExceptionCaught);
            }
        }
예제 #3
0
        private void InternalSearch(CancellationToken cancelToken, PauseTokenSource pauseTokenSource)
        {
            ElapsedTimer.Start();
            var startTime = DateTime.Now;

            processedFiles = 0;
            var lastProgressUpdate = DateTime.MinValue;
            var progressUpdateItvl = TimeSpan.FromMilliseconds(300);

            void IncrementProgress(Action <TimeSpan> fn)
            {
                Interlocked.Increment(ref processedFiles);
                var pushUpdate = processedFiles == ScanProgressMaxValue ||
                                 lastProgressUpdate + progressUpdateItvl < DateTime.Now;

                if (!pushUpdate)
                {
                    return;
                }
                lastProgressUpdate = DateTime.Now;
                var timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks *
                                                       (ScanProgressMaxValue - (processedFiles + 1)) / (processedFiles + 1));

                fn(timeRemaining);
            }

            try {
                var st         = Stopwatch.StartNew();
                var reScanList = ScanFileList.Where(vf => (vf.mediaInfo == null && !vf.IsImage) || vf.grayBytes == null).ToList();
                ScanProgressMaxValue = reScanList.Count;
                Parallel.For(0, reScanList.Count, new ParallelOptions {
                    MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = cancelToken
                }, i => {
                    while (pauseTokenSource.IsPaused)
                    {
                        Thread.Sleep(50);
                    }
                    var entry = reScanList[i];

                    if (entry.mediaInfo == null && !entry.IsImage)
                    {
                        var ffProbe = new FFProbeWrapper.FFProbeWrapper();
                        var info    = ffProbe.GetMediaInfo(entry.Path);
                        if (info == null)
                        {
                            return;
                        }
                        entry.mediaInfo = info;
                    }

                    if (entry.grayBytes == null)
                    {
                        entry.grayBytes = entry.IsImage ? GetImageAsBitmaps(entry, positionList.Count) : GetVideoThumbnailAsBitmaps(entry, positionList);
                        if (entry.grayBytes == null)
                        {
                            return;
                        }
                    }

                    //report progress
                    IncrementProgress(remaining =>
                                      Progress?.Invoke(this,
                                                       new OwnScanProgress {
                        CurrentPosition = processedFiles,
                        CurrentFile     = entry.Path,
                        Elapsed         = ElapsedTimer.Elapsed,
                        Remaining       = remaining
                    }));
                });
                st.Stop();
                Logger.Instance.Info(string.Format(Properties.Resources.ThumbnailsFinished, st.Elapsed, processedFiles));
                processedFiles       = 0;
                ScanProgressMaxValue = ScanFileList.Count;
                st.Restart();
                startTime = DateTime.Now;

                var percentageDifference = 1.0f - Settings.Percent / 100f;

                Parallel.For(0, ScanFileList.Count,
                             new ParallelOptions {
                    MaxDegreeOfParallelism = Environment.ProcessorCount,
                    CancellationToken      = cancelToken
                },
                             i => {
                    while (pauseTokenSource.IsPaused)
                    {
                        Thread.Sleep(50);
                    }
                    foreach (var itm in ScanFileList)
                    {
                        if (itm == ScanFileList[i] || itm.IsImage && !ScanFileList[i].IsImage)
                        {
                            continue;
                        }
                        if (itm.grayBytes == null || itm.grayBytes.Count == 0)
                        {
                            continue;
                        }
                        if (ScanFileList[i].grayBytes == null || ScanFileList[i].grayBytes.Count == 0)
                        {
                            continue;
                        }
                        if (itm.grayBytes.Count != ScanFileList[i].grayBytes.Count)
                        {
                            continue;
                        }
                        var duplicateCounter = 0;
                        var percent          = new float[itm.grayBytes.Count];
                        for (var j = 0; j < itm.grayBytes.Count; j++)
                        {
                            percent[j] = ExtensionMethods.PercentageDifference2(itm.grayBytes[j],
                                                                                ScanFileList[i].grayBytes[j]);
                            if (percent[j] < percentageDifference)
                            {
                                duplicateCounter++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (duplicateCounter != itm.grayBytes.Count)
                        {
                            continue;
                        }


                        lock (AddDuplicateLock) {
                            var firstInList  = false;
                            var secondInList = false;
                            var groupId      = Guid.NewGuid();
                            foreach (var v in Duplicates)
                            {
                                if (v.Path == itm.Path)
                                {
                                    groupId     = v.GroupId;
                                    firstInList = true;
                                }
                                else if (v.Path == ScanFileList[i].Path)
                                {
                                    secondInList = true;
                                }
                            }
                            if (!firstInList)
                            {
                                var origDup = new DuplicateItem(itm, percent.Average())
                                {
                                    GroupId = groupId
                                };
                                var origImages = itm.IsImage ? GetImageThumbnail(origDup, positionList.Count) : GetVideoThumbnail(origDup, positionList);
                                if (origImages == null)
                                {
                                    continue;
                                }
                                origDup.Thumbnail = origImages;
                                Duplicates.Add(origDup);
                            }

                            if (!secondInList)
                            {
                                var dup = new DuplicateItem(ScanFileList[i], percent.Average())
                                {
                                    GroupId = groupId
                                };
                                var images = ScanFileList[i].IsImage ? GetImageThumbnail(dup, positionList.Count) : GetVideoThumbnail(dup, positionList);
                                if (images == null)
                                {
                                    continue;
                                }
                                dup.Thumbnail = images;
                                Duplicates.Add(dup);
                            }
                        }

                        //we found a matching source then duplicate was added no need to go deeper
                        break;
                    }

                    //report progress
                    IncrementProgress(remaining =>
                                      Progress?.Invoke(this,
                                                       new OwnScanProgress {
                        CurrentPosition = processedFiles,
                        CurrentFile     = ScanFileList[i].Path,
                        Elapsed         = ElapsedTimer.Elapsed,
                        Remaining       = remaining
                    }));
                });

                st.Stop();
                Logger.Instance.Info(string.Format(Properties.Resources.DuplicatesCheckFinishedIn, st.Elapsed));
            }
            catch (OperationCanceledException) {
                Logger.Instance.Info(Properties.Resources.CancellationExceptionCaught);
            }
        }