protected virtual void Dispose(bool disposing) { if (disposed) { return; } if (disposing) { Stop(); int count = 50; while (PrefetchingBgWorker.IsBusy && count > 0) { Task.Delay(100).GetAwaiter().GetResult(); count--; } if (CanPrefetching is SemaphoreSlim && CanPrefetching.CurrentCount < 1) { CanPrefetching.Release(); } PrefetchingBgWorker.Dispose(); PrefetchedList.Clear(); Items.Clear(); } disposed = true; }
private void PrefetchingTask_DoWork(object sender, DoWorkEventArgs e) { List <string> illusts = new List <string>(); List <string> originals = new List <string>(); List <string> avatars = new List <string>(); List <string> page_thumbs = new List <string>(); List <string> page_previews = new List <string>(); List <string> needUpdate = new List <string>(); try { var args = e.Argument is PrefetchingOpts ? e.Argument as PrefetchingOpts : new PrefetchingOpts(); if (!args.PrefetchingPreview) { return; } LastStartTime = DateTime.Now; var pagesCount = CalcPagesThumbItems(Items); GetPreviewItems(illusts, avatars, page_thumbs, page_previews, originals); if (pagesCount != page_thumbs.Count + page_previews.Count) { e.Cancel = true; return; } var total = illusts.Count + avatars.Count + page_thumbs.Count + page_previews.Count; if (total <= 0) { e.Cancel = true; return; } var count = total; Percentage = count == 0 ? 100 : 0; Comments = $"Calculating [ {count} / {total}, I:{illusts.Count} / A:{avatars.Count} / T:{page_thumbs.Count} / P:{page_previews.Count} ]"; State = TaskStatus.WaitingToRun; if (ReportProgressSlim is Action) { ReportProgressSlim.Invoke(async: false); } else if (ReportProgress is Action <double, string, TaskStatus> ) { ReportProgress.Invoke(Percentage, Comments, State); } needUpdate.AddRange(args.ReverseOrder ? illusts.Reverse <string>() : illusts); needUpdate.AddRange(args.ReverseOrder ? avatars.Reverse <string>() : avatars); needUpdate.AddRange(args.ReverseOrder ? page_thumbs.Reverse <string>() : page_thumbs); needUpdate.AddRange(args.ReverseOrder ? page_previews.Reverse <string>() : page_previews); foreach (var url in needUpdate.Where(url => !PrefetchedList.ContainsKey(url) && File.Exists(url.GetImageCacheFile()))) { PrefetchedList.AddOrUpdate(url, true, (k, v) => true); //if (!PrefetchedList.TryAdd(url, true)) PrefetchedList.TryUpdate(url, true, false); } needUpdate = needUpdate.Where(url => !PrefetchedList.ContainsKey(url) || !PrefetchedList[url]).ToList(); count = needUpdate.Count; Percentage = count == 0 ? 100 : (total - count) / (double)total * 100; if (count == 0) { Comments = $"Done [ {count} / {total}, I:{illusts.Count} / A:{avatars.Count} / T:{page_thumbs.Count} / P:{page_previews.Count} ]"; State = TaskStatus.RanToCompletion; } else { Comments = $"Prefetching [ {count} / {total}, I:{illusts.Count} / A:{avatars.Count} / T:{page_thumbs.Count} / P:{page_previews.Count} ]"; State = TaskStatus.Running; } if (ReportProgressSlim is Action) { ReportProgressSlim.Invoke(async: false); } else if (ReportProgress is Action <double, string, TaskStatus> ) { ReportProgress.Invoke(Percentage, Comments, State); } this.DoEvents(); if (count == 0) { return; } var parallels = args.PrefetchingDownloadParallel; if (args.ParallelPrefetching) { var opt = new ParallelOptions(); opt.MaxDegreeOfParallelism = parallels; Parallel.ForEach(needUpdate, opt, (url, loopstate, urlIndex) => { try { var file = url.GetImageCacheFile(); if (!string.IsNullOrEmpty(file)) { if (File.Exists(file)) { PrefetchedList.AddOrUpdate(url, true, (k, v) => true); //if (!PrefetchedList.TryAdd(url, true)) PrefetchedList.TryUpdate(url, true, false); count = count - 1; } else { var _downReport = DownloadProgressActions.ContainsKey(url) ? DownloadProgressActions[url] : null; file = url.DownloadCacheFile(args.Overwrite, progressAction: _downReport, cancelToken: PrefetchingTaskCancelTokenSource).GetAwaiter().GetResult(); if (!string.IsNullOrEmpty(file)) { PrefetchedList.AddOrUpdate(url, true, (k, v) => true); //if (!PrefetchedList.TryAdd(url, true)) PrefetchedList.TryUpdate(url, true, false); count = count - 1; } } } if (PrefetchingBgWorker.CancellationPending) { e.Cancel = true; State = TaskStatus.Canceled; loopstate.Stop(); } Percentage = count == 0 ? 100 : (total - count) / (double)total * 100; Comments = $"Prefetching [ {count} / {total}, I:{illusts.Count} / A:{avatars.Count} / T:{page_thumbs.Count} / P:{page_previews.Count} ]"; State = TaskStatus.Running; if (ReportProgressSlim is Action) { ReportProgressSlim.Invoke(async: false); } else if (ReportProgress is Action <double, string, TaskStatus> ) { ReportProgress.Invoke((double)this.Percentage, Comments, State); } this.DoEvents(); } catch (Exception ex) { ex.ERROR("PREFETCHING"); } finally { this.DoEvents(); Task.Delay(1).GetAwaiter().GetResult(); } }); } else { SemaphoreSlim tasks = new SemaphoreSlim(parallels, parallels); foreach (var url in needUpdate) { if (PrefetchingBgWorker.CancellationPending) { e.Cancel = true; break; } if (tasks.Wait(-1, PrefetchingTaskCancelTokenSource.Token)) { new Action(async() => { try { var file = url.GetImageCacheFile(); if (!string.IsNullOrEmpty(file)) { if (File.Exists(file)) { PrefetchedList.AddOrUpdate(url, true, (k, v) => true); //if (!PrefetchedList.TryAdd(url, true)) PrefetchedList.TryUpdate(url, true, false); count = count - 1; } else { var _downReport = DownloadProgressActions.ContainsKey(url) ? DownloadProgressActions[url] : null; file = await url.DownloadCacheFile(args.Overwrite, progressAction: _downReport, cancelToken: PrefetchingTaskCancelTokenSource); if (!string.IsNullOrEmpty(file)) { PrefetchedList.AddOrUpdate(url, true, (k, v) => true); //if (!PrefetchedList.TryAdd(url, true)) PrefetchedList.TryUpdate(url, true, false); count = count - 1; } } } if (PrefetchingBgWorker.CancellationPending) { e.Cancel = true; State = TaskStatus.Canceled; return; } Percentage = count == 0 ? 100 : (total - count) / (double)total * 100; Comments = $"Prefetching [ {count} / {total}, I:{illusts.Count} / A:{avatars.Count} / T:{page_thumbs.Count} / P:{page_previews.Count} ]"; State = TaskStatus.Running; if (ReportProgressSlim is Action) { ReportProgressSlim.Invoke(async: false); } else if (ReportProgress is Action <double, string, TaskStatus> ) { ReportProgress.Invoke(Percentage, Comments, State); } //await Task.Delay(10); this.DoEvents(); } catch (Exception ex) { ex.ERROR("PREFETCHING"); } finally { if (tasks is SemaphoreSlim && tasks.CurrentCount <= parallels) { tasks.Release(); } this.DoEvents(); await Task.Delay(1); } }).Invoke(async: false); } } this.DoEvents(); } if (PrefetchingBgWorker.CancellationPending) { e.Cancel = true; State = TaskStatus.Canceled; return; } if (count >= 0 && total > 0) { Percentage = count == 0 ? 100 : (total - count) / (double)total * 100; Comments = $"Done [ {count} / {total}, I:{illusts.Count} / A:{avatars.Count} / T:{page_thumbs.Count} / P:{page_previews.Count} ]"; //State = TaskStatus.RanToCompletion; //if (ReportProgressSlim is Action) ReportProgressSlim.Invoke(async: false); //else if (ReportProgress is Action<double, string, TaskStatus>) ReportProgress.Invoke(Percentage, Comments, State); //this.DoEvents(); $"Prefetching Previews, Avatars, Thumbnails : {Environment.NewLine} {Comments}".ShowToast("INFO", tag: args.Name ?? Name ?? GetType().Name); } } catch (Exception ex) { ex.ERROR("PREFETCHING"); Comments = $"Failed {Comments}"; State = TaskStatus.Faulted; if (ReportProgressSlim is Action) { ReportProgressSlim.Invoke(async: false); } else if (ReportProgress is Action <double, string, TaskStatus> ) { ReportProgress.Invoke(Percentage, Comments, State); } } finally { try { GetOriginalImageSize(originals, e); if (ReportProgressSlim is Action) { ReportProgressSlim.Invoke(async: false); } else if (ReportProgress is Action <double, string, TaskStatus> ) { ReportProgress.Invoke(Percentage, Comments, State); } this.DoEvents(); illusts.Clear(); avatars.Clear(); page_thumbs.Clear(); page_previews.Clear(); originals.Clear(); needUpdate.Clear(); } catch (Exception ex) { ex.ERROR("PREFETCHED"); } if (CanPrefetching is SemaphoreSlim && CanPrefetching.CurrentCount < 1) { CanPrefetching.Release(); } LastStartTime = DateTime.Now; } }