Ejemplo n.º 1
0
        private ComplexSearch ConvertComplexSearch(SparkImageViewer.DataModel.ComplexSearchSetting source)
        {
            var result = new ComplexSearch(source.IsOr);

            source.SavedChildren.ForEach(x =>
            {
                var child = x.IsUnit
                    ? (ISqlSearch)this.ConvertUnitSearch((SparkImageViewer.DataModel.UnitSearchSetting)x)
                    : (ISqlSearch)this.ConvertComplexSearch((SparkImageViewer.DataModel.ComplexSearchSetting)x);
                result.Add(child);
            });

            return(result);
        }
Ejemplo n.º 2
0
        private async Task RefreshLibraryMainAsync(string[] added, string[] removed)
        {
            //登録解除されたフォルダ内のファイルは削除扱い

            var folderIgnoredRecords = new Dictionary <string, Record>();

            if (this.IgnoredFolders != null && this.IgnoredFolders.Length > 0)
            {
                var complex = new ComplexSearch(true);

                this.IgnoredFolders.Select(x => new UnitSearch()
                {
                    Property  = FileProperty.DirectoryPathStartsWith,
                    Reference = PathUtility.WithoutPostSeparator(x),
                    Mode      = CompareMode.Equal,
                })
                .ForEach(x => complex.Add(x));

                var folderFilter = complex.ToSql();

                if (folderFilter != null)
                {
                    var filter = DatabaseExpression.And
                                     (DatabaseExpression.IsFalse(nameof(Record.IsGroup)), folderFilter);

                    using (var connection = this.Records.Parent.Connect())
                    {
                        folderIgnoredRecords = (await this.Records
                                                .AsQueryable(connection)
                                                .Where(filter)
                                                .ToArrayAsync())
                                               .ToDictionary(x => x.Id, x => x);
                    }
                }
            }


            //列挙結果を保管する辞書
            var addedFiles   = new Dictionary <string, Record>();
            var removedFiles = new Dictionary <string, Record>(folderIgnoredRecords);
            var updatedFiles = new Dictionary <string, Record>();
            var skippedFiles = new HashSet <string>();

            var prospectedTags = new ConcurrentDictionary <string, ConcurrentBag <TagManager> >();

            //登録フォルダ内の全ファイルを列挙
            //ストレージアクセスきついので直列で処理
            foreach (var folder in this.Folders.Where(x => x.RefreshEnable))
            {
                //このフォルダ配下のファイル
                Record[] array;

                using (var connection = this.Records.Parent.Connect())
                {
                    array = await this.Records.AsQueryable(connection)
                            .Where(DatabaseExpression.And(DatabaseExpression.IsFalse(nameof(Record.IsGroup)),
                                                          FileProperty.DirectoryPathStartsWith.ToSearch(folder.Path, CompareMode.Equal)))
                            .ToArrayAsync();
                }

                var relatedFiles = new ReadOnlyDictionary <string, Record>
                                       (array.ToDictionary(x => x.Id, x => x));


                var tf = new FolderFileDetection(this.Config);

                tf.ChildFolderLoaded += x => this.LoadingSubject.OnNext(x);
                tf.FileLoaded        += x => this.FileLoadedSubject.OnNext(x);
                tf.FileEnumerated    += x => this.FileEnumeratedSubject.OnNext(x);

                var result = await tf.ListupFilesAsync
                                 (folder, relatedFiles, this.Completely, this.Level, prospectedTags)
                             .ConfigureAwait(false);

                //見つかったファイルを登録,重複していたら上書き
                tf.AddedFiles.ForEach(x => addedFiles[x.Key]     = x.Value);
                tf.RemovedFiles.ForEach(x => removedFiles[x.Key] = x.Value);
                tf.UpdatedFiles.ForEach(x => updatedFiles[x.Key] = x.Value);
                tf.SkippedFiles.ForEach(x => skippedFiles.Add(x));
            }

            this.LoadingSubject.OnNext("");


            //画像を読み込めなかったファイルも削除
            using (var connection = this.Records.Parent.Connect())
            {
                var notFoundRecords = await this.Records
                                      .AsQueryable(connection)
                                      .Where(DatabaseExpression.And(DatabaseExpression.IsTrue(nameof(Record.IsNotFound)),
                                                                    DatabaseExpression.IsFalse(nameof(Record.IsGroup))))
                                      .ToArrayAsync();

                foreach (var f in notFoundRecords)
                {
                    if (!removedFiles.ContainsKey(f.Id))
                    {
                        removedFiles[f.Id] = f;
                    }
                }
            }


            var topPathList = this.Folders
                              .Where(x => !x.IsIgnored)
                              .Select(x => x.Path)
                              .OrderBy(x => x)
                              .ToArray();

            if (added != null && removed != null)
            {
                ReadOnlyDictionary <string, Record> relatedFiles;

                using (var connection = this.Records.Parent.Connect())
                {
                    var items = added.Concat(removed).Distinct().ToArray();
                    var r     = await this.Records.GetRecordsFromKeyAsync(connection, items);

                    relatedFiles = new ReadOnlyDictionary <string, Record>
                                       (r.ToDictionary(x => x.Id, x => x));
                }


                var tf = new FolderFileDetection(this.Config);

                tf.ChildFolderLoaded += x => this.LoadingSubject.OnNext(x);
                tf.FileLoaded        += x => this.FileLoadedSubject.OnNext(x);
                tf.FileEnumerated    += x => this.FileEnumeratedSubject.OnNext(x);

                var result = await tf.CheckFolderUpdateAsync(added, this.Level, relatedFiles, prospectedTags)
                             .ConfigureAwait(false);

                //見つかったファイルを登録,重複していたら上書き
                tf.AddedFiles.ForEach(x => addedFiles[x.Key]     = x.Value);
                tf.RemovedFiles.ForEach(x => removedFiles[x.Key] = x.Value);
                tf.UpdatedFiles.ForEach(x => updatedFiles[x.Key] = x.Value);
                tf.SkippedFiles.ForEach(x => skippedFiles.Add(x));
            }

            //ファイルにキーワードが設定されていたらタグとして設定
            foreach (var item in prospectedTags)
            {
                var id = this.TagDictionary.SetTag(new TagInformation()
                {
                    Name = item.Key
                });
                item.Value.ForEach(x => x.Add(id));
            }

            //更新結果
            addedFilesResult   = new Dictionary <string, Record>(addedFiles);
            removedFilesResult = new Dictionary <string, Record>(removedFiles);
            updatedFilesResult = new Dictionary <string, Record>(updatedFiles);

            var missLoadedItems = new HashSet <string>();


            //旧ライブラリにあって新ライブラリに無いファイル=削除された可能性のあるファイル
            //本当に無いのか確認
            foreach (var file in removedFiles)
            {
                //ファイル名が同じなら同じファイルが移動したと判断
                var filesWithSameName = addedFilesResult
                                        .Where(x => x.Value.FileName.Equals(file.Value.FileName))
                                        .ToList();

                if (filesWithSameName.Count == 1)
                {
                    this.MarkAsUpdated(file, filesWithSameName[0]);
                    continue;
                }

                //別フォルダに移動しているか
                if (!topPathList.IsNullOrEmpty())
                {
                    var relativePath = file.Value.FileName;
                    foreach (var topPath in topPathList)
                    {
                        if (file.Value.Directory.StartsWith(topPath))
                        {
                            relativePath = file.Value.FullPath.Substring(topPath.Length);
                            break;
                        }
                    }
                    var filesWithSamePath = addedFilesResult
                                            .Where(x => x.Value.FullPath.EndsWith(relativePath))
                                            .ToList();

                    if (filesWithSamePath.Count == 1)
                    {
                        this.MarkAsUpdated(file, filesWithSamePath[0]);
                        continue;
                    }
                }

                //プロパティが一致するものが一つだけあれば同じものと判断
                var filesWithSameProperty = addedFilesResult
                                            .Where(x => x.Value.DateCreated == file.Value.DateCreated &&
                                                   x.Value.Size == file.Value.Size &&
                                                   x.Value.DateModified == file.Value.DateModified &&
                                                   x.Value.Height == file.Value.Height &&
                                                   x.Value.Width == file.Value.Width)
                                            .ToList();

                if (filesWithSameProperty.Count == 1)
                {
                    this.MarkAsUpdated(file, filesWithSameProperty[0]);
                    continue;
                }

                //本当にファイルが存在しないのか確認
                if (!folderIgnoredRecords.ContainsKey(file.Key))
                {
                    if (await this.Config.IsFileExistsAsync(file.Value))
                    {
                        missLoadedItems.Add(file.Key);
                        removedFilesResult.Remove(file.Key);
                    }
                }
            }
            foreach (var key in missLoadedItems)
            {
                removedFiles.Remove(key);
            }



            //データベース更新

            using (var connection = this.Records.Parent.ConnectAsThreadSafe())
            {
                //削除
                this.Records.RemoveRangeBuffered(connection.Value, removedFiles.Select(x => x.Value));

                //追加・更新
                var dateNow = DateTimeOffset.Now;
                foreach (var item in addedFiles)
                {
                    item.Value.DateRegistered = dateNow;
                }
                await this.Records.AddRangeBufferedAsync(connection.Value,
                                                         addedFiles.Select(x => x.Value).Concat(updatedFiles.Select(x => x.Value)), true);


                //関連するグループの情報を更新
                var groups = addedFiles.Select(x => x.Value.GroupKey)
                             .Union(updatedFiles.Select(x => x.Value.GroupKey))
                             .Union(removedFiles.Select(x => x.Value.GroupKey))
                             .Where(x => !x.IsNullOrWhiteSpace())
                             .ToArray();

                await library.Grouping.RefreshGroupPropertiesAsync(connection.Value, groups);
            }

            this.CompletingTask();

            this.LoadingSubject.OnNext(null);
        }