// -------------------------------------------------------------------- // 親フォルダーの IsOpen をサブフォルダーの Visible に反映 // -------------------------------------------------------------------- public void UpdateTargetFolderInfosVisible(TargetFolderInfo parentFolder) { lock (_targetFolderInfos) { Int32 parentIndex = IndexOfTargetFolderInfoWithoutLock(parentFolder.TargetPath); if (parentIndex < 0) { return; } if (parentFolder.IsOpen == true) { SetTargetFolderInfosVisibleToTrue(parentIndex); } else { // すべてのサブフォルダーを非表示にする for (Int32 i = parentIndex + 1; i < parentIndex + parentFolder.NumTotalFolders; i++) { _targetFolderInfos[i].Visible = false; } } } YlModel.Instance.EnvModel.IsMainWindowDataGridCountChanged = true; }
// -------------------------------------------------------------------- // 検出ファイルリストテーブルにファイル情報を追加 // AddFileNames() で追加されない情報をすべて付与する // ファイルは再帰検索しない // -------------------------------------------------------------------- private static void AddInfosCore(TargetFolderInfo targetFolderInfo) { // フォルダー設定を読み込む FolderSettingsInDisk folderSettingsInDisk = YlCommon.LoadFolderSettings(targetFolderInfo.TargetPath); FolderSettingsInMemory folderSettingsInMemory = YlCommon.CreateFolderSettingsInMemory(folderSettingsInDisk); using ListContextInMemory listContextInMemory = new(); using TFoundSetter foundSetter = new(listContextInMemory); // 指定フォルダーの全レコード IQueryable <TFound> targetRecords = listContextInMemory.Founds.Where(x => x.Folder == targetFolderInfo.TargetPath); // 情報付与 foreach (TFound record in targetRecords) { FileInfo fileInfo = new(record.Path); record.LastWriteTime = JulianDay.DateTimeToModifiedJulianDate(fileInfo.LastWriteTime); record.FileSize = fileInfo.Length; foundSetter.SetTFoundValues(record, folderSettingsInMemory); YlModel.Instance.EnvModel.AppCancellationTokenSource.Token.ThrowIfCancellationRequested(); } AddFolderTagsInfo(targetFolderInfo, targetRecords, listContextInMemory.Tags, listContextInMemory.TagSequences); // コミット listContextInMemory.SaveChanges(); }
// -------------------------------------------------------------------- // targetFolderInfo の NumTotalFolders が delta 増減したので、上位の NumTotalFolders を調整する // targetFolderInfo の NumTotalFolders はいじらない // -------------------------------------------------------------------- public void AdjustNumTotalFolders(TargetFolderInfo targetFolderInfo, Int32 delta) { lock (_targetFolderInfos) { Int32 index = IndexOfTargetFolderInfoWithoutLock(targetFolderInfo.TargetPath); if (index < 0) { return; } AdjustNumTotalFoldersWithoutLock(index, delta); } }
// ==================================================================== // private 関数 // ==================================================================== // -------------------------------------------------------------------- // 検出ファイルリストテーブルにファイル名を追加 // -------------------------------------------------------------------- private void AddFileNames(TargetFolderInfo targetFolderInfo) { // 動作状況設定 SetFolderTaskStatus(targetFolderInfo, FolderTaskStatus.Running); // 作業 AddFileNamesCore(targetFolderInfo); // 動作状況設定 targetFolderInfo.SetFolderTaskDetail(FolderTaskDetail.AddFileNames, FolderTaskDetail.AddInfos); SetFolderTaskStatus(targetFolderInfo, FolderTaskStatus.Queued); _prevFolderTaskDetail = FolderTaskDetail.AddFileNames; }
// -------------------------------------------------------------------- // ゆかり検索対象フォルダーにサブフォルダー群を追加 // -------------------------------------------------------------------- public void AddTargetSubFolders(TargetFolderInfo parentFolder, List <TargetFolderInfo> subFolders) { lock (_targetFolderInfos) { Int32 parentIndex = IndexOfTargetFolderInfoWithoutLock(parentFolder.TargetPath); if (parentIndex < 0) { return; } _targetFolderInfos.InsertRange(parentIndex + 1, subFolders); } // サブフォルダーは非表示なのでアイテム数は変わらない、親のノブ表示が変わる YlModel.Instance.EnvModel.IsMainWindowDataGridItemUpdated = true; }
// -------------------------------------------------------------------- // キャッシュ DB からディスク DB へコピー // -------------------------------------------------------------------- private static void CacheToDiskCore(TargetFolderInfo targetFolderInfo) { try { using CacheContext cacheContext = new(YlCommon.DriveLetter(targetFolderInfo.TargetPath)); cacheContext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; // QueryTrackingBehavior.NoTracking(または AsNoTracking())時、結果の内容を変更して使いたい時は IQueryable<T> で受けてはならない(インスタンスの内容が変更できない) // List<T> 等に変換すれば結果のインスタンス内容を変更できる(変更しても SaveChanges() の対象にはならないと思う) List <TFound> cacheRecords = cacheContext.Founds.Where(x => x.ParentFolder == targetFolderInfo.TargetPath).ToList(); if (!cacheRecords.Any()) { // キャッシュが見つからない場合、ドライブレター以外の部分で合致するか再度検索 // 誤検知しないようコロンも含めて検索するので、YlCommon.WithoutDriveLetter() は使用しない String withoutDriveLetterOne = targetFolderInfo.TargetPath[1..];
// -------------------------------------------------------------------- // 検出ファイルリストテーブルに属性を追加 // -------------------------------------------------------------------- private void AddInfos(TargetFolderInfo targetFolderInfo) { // 動作状況設定 SetFolderTaskStatus(targetFolderInfo, FolderTaskStatus.Running); YlModel.Instance.EnvModel.LogWriter.LogMessage(Common.TRACE_EVENT_TYPE_STATUS, "属性確認中... " + targetFolderInfo.TargetPath); // 作業 AddInfosCore(targetFolderInfo); #if DEBUGz Thread.Sleep(500); #endif // 動作状況設定 targetFolderInfo.SetFolderTaskDetail(FolderTaskDetail.AddInfos, FolderTaskDetail.Done); SetFolderTaskStatus(targetFolderInfo, FolderTaskStatus.DoneInMemory); _prevFolderTaskDetail = FolderTaskDetail.AddInfos; }
// -------------------------------------------------------------------- // キャッシュ DB からディスク DB へコピー // -------------------------------------------------------------------- private void CacheToDisk(TargetFolderInfo targetFolderInfo) { Debug.Assert(targetFolderInfo.IsParent, "CacheToDisk() not parent"); // 動作状況設定 SetFolderTaskStatus(targetFolderInfo, FolderTaskStatus.Running); // 作業 CacheToDiskCore(targetFolderInfo); #if TEST YlModel.Instance.EnvModel.LogWriter.ShowLogMessage(TraceEventType.Information, "CacheToDisk() キャッシュ追加:" + targetFolderInfo.TargetPath); #endif // 動作状況設定 targetFolderInfo.SetFolderTaskDetail(FolderTaskDetail.CacheToDisk, FolderTaskDetail.FindSubFolders); SetFolderTaskStatus(targetFolderInfo, FolderTaskStatus.Queued); _prevFolderTaskDetail = FolderTaskDetail.CacheToDisk; #if DEBUGz Thread.Sleep(60 * 1000); #endif }
// -------------------------------------------------------------------- // フォルダー設定で指定されているタグを TFound とゆかり用リストデータベースに付与する // -------------------------------------------------------------------- private static void AddFolderTagsInfo(TargetFolderInfo targetFolderInfo, IQueryable <TFound> records, DbSet <TTag> tags, DbSet <TTagSequence> tagSequences) { try { String tagKey = YlCommon.WithoutDriveLetter(targetFolderInfo.TargetPath); if (!YlModel.Instance.EnvModel.TagSettings.FolderTags.ContainsKey(tagKey)) { return; } // TTag にフォルダー設定のタグ情報と同名のタグがあるか? String tagValue = YlModel.Instance.EnvModel.TagSettings.FolderTags[tagKey]; TTag? tagRecord = DbCommon.SelectMasterByName(tags, tagValue); if (tagRecord == null) { // 同名のタグが無いので、tagKey を Id とするタグがまだ存在しなければ作成 String tagId = YlConstants.TEMP_ID_PREFIX + tagKey; tagRecord = DbCommon.SelectBaseById(tags, tagId); if (tagRecord == null) { tagRecord = new() { // IRcBase Id = tagId, Import = false, Invalid = false, UpdateTime = YlConstants.INVALID_MJD, Dirty = true, // IRcMaster Name = tagValue, Ruby = null, Keyword = null, }; tags.Add(tagRecord); } } Dictionary <String, Boolean> addedIds = new(); foreach (TFound record in records) { // TFound にタグ情報を追加 // 楽曲情報データベースで付与されたものと同じ場合は重複連結となるが、ゆかりが検索するためのものなので問題ない record.TagName += "," + tagRecord.Name; if (!String.IsNullOrEmpty(tagRecord.Ruby)) { record.TagRuby += "," + tagRecord.Ruby; } // ゆかり用リストデータベースの TTagSequence にタグ情報を追加 // 1 つのフォルダー内に同じ曲が複数個存在する場合があるので、既に作業済みの曲はスキップ if (String.IsNullOrEmpty(record.SongId) || addedIds.ContainsKey(record.SongId)) { continue; } // TTagSequence にフォルダー設定のタグ情報が無ければ保存 List <TTag> songTags = DbCommon.SelectSequencedTagsBySongId(tagSequences, tags, record.SongId); if (songTags.FirstOrDefault(x => x.Name == tagRecord.Name) == null) { IQueryable <Int32> sequenceResults = tagSequences.Where(x => x.Id == record.SongId).Select(x => x.Sequence); Int32 seqMax = sequenceResults.Any() ? sequenceResults.Max() : -1; TTagSequence tagSequenceRecord = new() { // IDbBase Id = record.SongId, Import = false, Invalid = false, UpdateTime = YlConstants.INVALID_MJD, Dirty = true, // IDbSequence Sequence = seqMax + 1, LinkId = tagRecord.Id, }; tagSequences.Add(tagSequenceRecord); addedIds[record.SongId] = true; } } } catch (Exception ex) { YlModel.Instance.EnvModel.NebulaCoreErrors.Enqueue("フォルダー設定タグ付与時エラー:\n" + ex.Message); YlModel.Instance.EnvModel.LogWriter.LogMessage(Common.TRACE_EVENT_TYPE_STATUS, " スタックトレース:\n" + ex.StackTrace); } }
// -------------------------------------------------------------------- // 指定フォルダ内のファイルを検索してゆかり用データベースに追加 // ユニーク ID、フルパス、フォルダーのみ記入する // ファイルは再帰検索しない // -------------------------------------------------------------------- private void AddFileNamesCore(TargetFolderInfo targetFolderInfo) { // フォルダー除外設定を読み込む if (YlCommon.DetectFolderExcludeSettingsStatus(targetFolderInfo.TargetPath) == FolderExcludeSettingsStatus.True) { return; } // Uid using ListContextInMemory listContextInMemory = new(); Int64 uid = listContextInMemory.Founds.Any() ? listContextInMemory.Founds.Max(x => x.Uid) + 1 : 1; // キャッシュが使われていない場合はディスク DB の Uid とも重複しないようにする(全体の動作状況がエラーではない場合のみ) if (YlModel.Instance.EnvModel.YukaListerWholeStatus != YukaListerStatus.Error && !targetFolderInfo.IsCacheUsed) { using ListContextInDisk listContextInDisk = new(); if (listContextInDisk.Founds.Any()) { uid = Math.Max(uid, listContextInDisk.Founds.Max(x => x.Uid) + 1); } } // 検索 String[] allPathes; try { allPathes = Directory.GetFiles(targetFolderInfo.TargetPath); } catch (Exception) { return; } // 追加準備 List <TFound> addRecords = new(); addRecords.Capacity = allPathes.Length; foreach (String path in allPathes) { if (!YlModel.Instance.EnvModel.YlSettings.TargetExts.Contains(Path.GetExtension(path).ToLower())) { continue; } TFound record = new(); record.Uid = uid; record.Path = path; record.Folder = Path.GetDirectoryName(path) ?? String.Empty; record.ParentFolder = targetFolderInfo.ParentPath; // 楽曲名とファイルサイズが両方とも初期値だと、ゆかりが検索結果をまとめてしまうため、ダミーのファイルサイズを入れる // (文字列である楽曲名を入れると処理が遅くなるので処理が遅くなりにくい数字のファイルサイズをユニークにする) record.FileSize = -uid; addRecords.Add(record); uid++; } // メモリー DB に追加 listContextInMemory.Founds.AddRange(addRecords); listContextInMemory.SaveChanges(); _needsMemoryDbToDiskDb = true; _needsMemoryDbToCacheDb = true; // キャッシュが使われていない場合はディスク DB にも追加(全体の動作状況がエラーではない場合のみ) if (YlModel.Instance.EnvModel.YukaListerWholeStatus != YukaListerStatus.Error && !targetFolderInfo.IsCacheUsed) { using ListContextInDisk listContextInDisk = new(); listContextInDisk.Founds.AddRange(addRecords); listContextInDisk.SaveChanges(); YlModel.Instance.EnvModel.LogWriter.LogMessage(Common.TRACE_EVENT_TYPE_STATUS, "ゆかり用リストデータベースにファイル名を追加しました。" + targetFolderInfo.TargetPath); } }